You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 14863f6
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: README.md
+28-9Lines changed: 28 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -103,8 +103,15 @@ interface RunnerEvent {
103
103
|`task.finished`| The agent finished. Now awaiting approval |`total_cost_usd`, `usage`, `num_turns`, `result`, `diffStat`|
104
104
|`task.failed`| The run cannot continue |`reason`, plus details |
105
105
|`task.stopped`| A person stopped it ||
106
+
|`step.started`| v0.2.0. The engine began a step |`step`|
107
+
|`step.finished`| v0.2.0. The engine ended a step |`step`, `ok`, `costUsd?`|
108
+
|`permission.denied`| v0.2.0. The agent tried something and was blocked |`tool`, `reason`, `input?`|
109
+
|`provider.status`| v0.2.0. The model provider can't serve the run |`state`, `message`, `code?` (HTTP status or CLI error), `retryAt?`|
110
+
|`approval.requested`| v0.2.0. Sent right after `task.finished`. The session is now `awaiting_approval`|`diffStat`|
106
111
107
-
Payloads are open on purpose in v0.1.0. The fields above are what the runner sends today; read them defensively.
112
+
Payloads are open on purpose. The fields above are what the runner sends today; read them defensively.
113
+
114
+
`step` is one of `ENGINE_STEPS`: `analyze`, `plan`, `implement`, `test`, `review`, always in that order. `state` is one of `PROVIDER_STATES`: `rate_limited`, `auth_expired`, `usage_limit`, `subscription_inactive`, `down`.
108
115
109
116
### The `Runner` interface
110
117
@@ -124,12 +131,24 @@ interface StartOptions {
124
131
sessionId:string; // a UUID, also reused as Claude Code's --session-id
125
132
repoPath:string;
126
133
prompt:string;
127
-
agent:"claude-code"|"codex";
128
-
model?:string;
134
+
agent:"claude-code"|"codex"|"codehands"; // "codehands" (the engine) since v0.2.0
135
+
model?:string; // one model for the whole run
136
+
models?:Partial<Record<StepName, string>>; // v0.2.0: per engine step, e.g. { plan: "claude-opus-5-5" }
129
137
budgetUsd?:number;
130
138
}
131
139
```
132
140
141
+
A step with no entry in `models` uses `model`.
142
+
143
+
`approve` and `reject` send no event. The promise is the outcome:
144
+
145
+
| Call | Resolves | Throws |
146
+
| --- | --- | --- |
147
+
|`approve`| Committed on the task's branch, worktree removed. Status `approved`| The status stays `awaiting_approval`. The error says why (for example, the agent changed nothing) |
148
+
|`reject`| Worktree and branch deleted. Status `rejected`| The status stays `awaiting_approval`. The error says why |
149
+
150
+
The daemon writes the new status and records the outcome itself.
151
+
133
152
`start` and `resume` return an async iterable, so the caller just loops:
134
153
135
154
```ts
@@ -140,16 +159,16 @@ for await (const event of runner.start(options)) {
140
159
141
160
## Contracts still to write
142
161
143
-
The design in [codehands-docs](https://github.com/devweekends/codehands-docs#contracts) names four contracts. v0.1.0 covers C5 and the first half of C2. The rest arrive as minor versions.
162
+
The design in [codehands-docs](https://github.com/devweekends/codehands-docs#contracts) names four contracts. The rest arrive as minor versions.
144
163
145
-
| ID | Contract |In v0.1.0| Still to add | Owner |
164
+
| ID | Contract |Done so far| Still to add | Owner |
146
165
| --- | --- | --- | --- | --- |
147
166
| L1 | Local DB: the tables in `~/.codehands/state.db` and which process may write each | No | Table types for `tasks`, `commands`, `sessions`, `events`, `provider_status`, and the writer of each | Midhat |
148
-
| C2 | Runner |`Runner`, `StartOptions`, events| Model per phase, preferences and memory in `StartOptions`; a `provider.status`event| Tahira |
149
-
| C3 | Cloud API |No | Sign up, log in, log out, device tokens; `push(changes)`, `pull(cursor)`; record versions| Memoona |
150
-
| C5 | Sessions | Yes|`Project` keyed by repo identity (a hash of the origin URL) instead of a folder path| Midhat, Tahira |
167
+
| C2 | Runner |`Runner`, `StartOptions`, events. v0.2.0: engine steps, model per step, `permission.denied`, `provider.status`| Preferences and memory in `StartOptions`| Tahira |
168
+
| C3 | Cloud API |Yes: sign up, log in, log out, devices, `push`, `pull` (`cloud-api.ts`) || Memoona |
169
+
| C5 | Sessions | Yes. v0.2.0:`Project.repoKey`, `Session.updatedAt`| Make `repoKey` and `updatedAt` required once every writer sets them| Midhat, Tahira |
151
170
152
-
The provider failure states the C2 event will carry are fixed already: `rate_limited`, `auth_expired`, `usage_limit`, `subscription_inactive`, `down`. Their meaning is in the [docs README](https://github.com/devweekends/codehands-docs#provider-failures).
171
+
The meaning of each provider failure state is in the [docs README](https://github.com/devweekends/codehands-docs#provider-failures).
0 commit comments