@agentskit/harness 0.4.0 → 0.6.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/CHANGELOG.md +29 -3
- package/README.md +9 -0
- package/capabilities/public-surface.json +571 -49
- package/compatibility/report.json +3 -3
- package/compatibility/report.md +1 -1
- package/dist/cli.js +3679 -157
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1786 -28
- package/dist/index.js +3640 -269
- package/dist/index.js.map +1 -1
- package/docs/ADR-0027-keep-pushing-loop.md +41 -0
- package/docs/ADR-0028-mcp-adapter-boundary.md +45 -0
- package/docs/LOOP.md +276 -0
- package/docs/MODULE-BOUNDARIES.md +37 -4
- package/docs/PRD-0.4.0.md +639 -0
- package/loop.config.example.yaml +157 -0
- package/package.json +38 -7
- package/release/manifest.json +29 -7
- package/release/notes.md +22 -3
- package/release/qualification.json +4 -4
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# ADR-0027: Keep-pushing loop as composition over Orca
|
|
2
|
+
|
|
3
|
+
- Status: Accepted
|
|
4
|
+
- Date: 2026-09-11
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
Teams want a coding-agent loop that drains one person's Linear queue around the clock: pick a ticket, freeze a
|
|
9
|
+
verifiable contract, run a worker in an isolated worktree, review, merge, repeat — while never exceeding the
|
|
10
|
+
machine, never guessing when acceptance criteria are missing, and surviving provider usage limits. The harness already
|
|
11
|
+
owns the deterministic pieces (dispatch ledger, machine pressure, delivery gates, evidence). Orca already owns
|
|
12
|
+
scheduling, worktrees, terminals, Linear access and the visibility surface. Nothing owned the composition.
|
|
13
|
+
|
|
14
|
+
## Decision
|
|
15
|
+
|
|
16
|
+
1. The loop lives in this package as **Adapter + Composition** (`src/adapters/{command,orca-cli,providers,linear-orca,
|
|
17
|
+
github-cli,code-review}.ts`, `src/loop/*`). The kernel is unchanged and never imports it (`pnpm test:boundaries`).
|
|
18
|
+
2. Every project-specific value lives in `loop.config.yaml` (zod-validated). The code carries no repository, person,
|
|
19
|
+
path or model id. Env variable **names** may appear in config; values never do.
|
|
20
|
+
3. External systems are reached only through argv-based, timeout-bounded process execution injected as a
|
|
21
|
+
`CommandRunner`. Adapters never spawn a shell; composition supplies the real runner; tests supply fakes.
|
|
22
|
+
4. Orca is the single scheduler and visibility surface: two automations (`<prefix>-tick`, `<prefix>-deliver`), each
|
|
23
|
+
gated by a read-only `--precheck` that exits 0 only when work exists, run an agent prompt whose sole job is to
|
|
24
|
+
invoke `ak-harness loop <stage>`. No cron, launchd or daemon of our own.
|
|
25
|
+
5. Model routing is tiered per role (`orchestrator`, `reviewer`, `builder`, `watcher`); within a tier the first
|
|
26
|
+
provider with usage available wins. Usage comes from `orca account list`; an auth/quota failure marks the provider
|
|
27
|
+
cooling down (exponential, never before the reset Orca reports) and the next candidate is tried.
|
|
28
|
+
6. Autonomy envelope: the loop may claim tickets, freeze contracts, dispatch workers, nudge them, review, squash-merge on
|
|
29
|
+
a clean review plus green checks, move Linear states and clean worktrees. It must not merge PRs touching
|
|
30
|
+
`selfEditPaths`, must not force-push or bypass approvals, must not recover leases (human only, ADR-0021), and must
|
|
31
|
+
escalate with one deduplicated comment when a contract has no executable acceptance criterion or when fix rounds
|
|
32
|
+
are exhausted.
|
|
33
|
+
|
|
34
|
+
## Consequences
|
|
35
|
+
|
|
36
|
+
- `yaml` and `zod` become runtime dependencies of the package.
|
|
37
|
+
- The loop is verifiable offline: every stage has fixture-driven tests and `--dry-run` prints the exact argv.
|
|
38
|
+
- Provider CLIs (`claude`, `codex`, `grok`, `opencode`) are configuration, not code; adding one is a YAML entry with a
|
|
39
|
+
TUI template, an optional headless template and an `agentskit-review` provider id.
|
|
40
|
+
- Windows is supported through Node's process model; WSL is detected and capped to one worker because host
|
|
41
|
+
antivirus load is invisible from the distro.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# ADR-0028: MCP is an adapter-only boundary
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
Accepted — 2026-09-11.
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
MCP (Model Context Protocol) is a useful integration surface for read-only
|
|
10
|
+
inspection and, later, gated tool calls. The keep-pushing loop and kernel must
|
|
11
|
+
remain usable without any MCP host, SDK, or network dependency. MODULE-BOUNDARIES
|
|
12
|
+
and ADR-0026 already classify MCP as an adapter concern; 0.6.0 needs an
|
|
13
|
+
explicit decision before any public bridge ships.
|
|
14
|
+
|
|
15
|
+
## Decision
|
|
16
|
+
|
|
17
|
+
1. **Adapter-only.** MCP lives under `src/adapters/mcp.ts` (and future adapter
|
|
18
|
+
modules). Kernel modules do not import MCP clients, hosts, or transports.
|
|
19
|
+
2. **Default-deny policy.** Every tool call goes through an allowlist
|
|
20
|
+
(`allowTools`) and a `PolicyGate` (or compatible `evaluate`). Missing
|
|
21
|
+
allowlist entry or non-`allow` decision returns `{ status: 'blocked' }`
|
|
22
|
+
without invoking the underlying call.
|
|
23
|
+
3. **Read-only profile first.** The initial public surface is a policy-gated
|
|
24
|
+
call bridge intended for read-only / inspection tools. Mutating MCP tools
|
|
25
|
+
require a later ADR covering authorization, idempotency, and audit evidence.
|
|
26
|
+
4. **Harness works without MCP.** Default loop config keeps `mcp.enabled: false`.
|
|
27
|
+
No MCP process is started by install, tick, or deliver.
|
|
28
|
+
5. **Not wired into loop tick/deliver in 0.6.0.** The bridge is exported for
|
|
29
|
+
composition and future CLI/doctor use. Tick and deliver must not call it in
|
|
30
|
+
this release.
|
|
31
|
+
|
|
32
|
+
## Consequences
|
|
33
|
+
|
|
34
|
+
- Consumers can plug MCP behind the same policy gate used by session tool
|
|
35
|
+
recording without coupling the kernel to a vendor host.
|
|
36
|
+
- Loop automation remains deterministic and offline-testable when MCP is off.
|
|
37
|
+
- A later release may wire a read-only MCP profile into doctor or a dedicated
|
|
38
|
+
CLI after eval coverage; mutating tools stay out until gated separately.
|
|
39
|
+
|
|
40
|
+
## Alternatives considered
|
|
41
|
+
|
|
42
|
+
- **Kernel MCP host:** rejected; violates ADR-0026 and forces an optional
|
|
43
|
+
network dependency into deterministic gates.
|
|
44
|
+
- **Wire MCP into tick/deliver now:** rejected for 0.6.0; needs allowlist
|
|
45
|
+
provenance, audit events, and eval coverage first.
|
package/docs/LOOP.md
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# Keep-pushing loop (`ak-harness loop`)
|
|
2
|
+
|
|
3
|
+
The loop drains one person's Linear queue through Orca worktrees, 24/7, with role-based model routing and
|
|
4
|
+
usage-aware fallback. The harness supplies the deterministic parts (claims, machine pressure, gates, evidence);
|
|
5
|
+
Orca supplies scheduling, worktrees, terminals, Linear access and visibility. Everything project-specific lives in
|
|
6
|
+
`loop.config.yaml` — switching project or person is a config change, never a code change.
|
|
7
|
+
|
|
8
|
+
Status: **complete (phases 1–5).** Config, doctor, adapters, the dispatch tick, the deliver stage and the Orca
|
|
9
|
+
automation installer are in place. See [ADR-0027](ADR-0027-keep-pushing-loop.md).
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
ak-harness loop validate -f loop.config.yaml # schema check + effective config + hash
|
|
15
|
+
ak-harness loop doctor -f loop.config.yaml --json # readiness report (exit 1 when a blocking check fails)
|
|
16
|
+
ak-harness loop doctor --no-probe # skip provider probe commands
|
|
17
|
+
ak-harness loop precheck tick # exit 0 when a slot, a builder and a candidate exist (Orca --precheck)
|
|
18
|
+
ak-harness loop tick --dry-run --max 1 # plan the next dispatch, print the exact orca argv, write nothing
|
|
19
|
+
ak-harness loop tick # dispatch up to <free slots> workers
|
|
20
|
+
ak-harness loop contract ENG-123 [--refresh|--dry-run] # freeze or show the orchestrator contract for one issue
|
|
21
|
+
ak-harness loop precheck deliver # exit 0 when a dispatched issue is in flight
|
|
22
|
+
ak-harness loop deliver [--dry-run] [--issue ENG-123] # drive dispatched workers to merge
|
|
23
|
+
ak-harness loop install [--yes|--force|--skip-rehearsal|--skip-local-config|--dry-run|--plain] # guided: overlay → checks → rehearsal → confirm
|
|
24
|
+
ak-harness loop uninstall [--dry-run] # remove them
|
|
25
|
+
ak-harness loop status # what Orca knows: enabled, trigger, provider, latest run
|
|
26
|
+
ak-harness loop hook # one status line for a SessionStart hook; never mutates
|
|
27
|
+
ak-harness loop debrief [--issue ENG-123] [--since 24h] # human-facing: what is in flight, held, escalated
|
|
28
|
+
ak-harness loop watch [--issue ENG-123] [--once] [--interval 30] # poll delivery/PR; DONE|FAILED|ACTION_REQUIRED
|
|
29
|
+
ak-harness loop retro [--since 7d] [--json|--learnings] # weekly digest + calibration suggestions
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Debrief and watch
|
|
33
|
+
|
|
34
|
+
`loop debrief` is the human companion to the automations: a read-only Markdown (or `--json`) snapshot of
|
|
35
|
+
in-flight dispatches, delivery phase (waiting for PR / review / fix round / ready to merge), holds that need a
|
|
36
|
+
person, recent escalations and provider cooldowns. It does not call Orca or `gh` — only the loop state directory —
|
|
37
|
+
so it is safe to run from a SessionStart hook or a chat agent that needs context before acting.
|
|
38
|
+
|
|
39
|
+
`loop watch` polls `delivery.json` (and optionally the live PR via `gh`) and prints line-oriented events:
|
|
40
|
+
|
|
41
|
+
| Event | Meaning |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `DONE` | Delivery finished as merged (or the PR is MERGED) |
|
|
44
|
+
| `FAILED` | stuck / abandoned / failed / PR closed without merge |
|
|
45
|
+
| `ACTION_REQUIRED` | held for a human, incomplete review twice, or fix-round findings |
|
|
46
|
+
| `PROGRESS` | still moving (waiting for PR, review pending, …) |
|
|
47
|
+
|
|
48
|
+
Use `--once` for a single snapshot; omit it to block until a terminal outcome (or `--timeout <seconds>`).
|
|
49
|
+
|
|
50
|
+
## Running 24/7 with Orca
|
|
51
|
+
|
|
52
|
+
`loop install` is guided and rendered with Ink when stdin/stdout are terminals (plain lines otherwise). When no
|
|
53
|
+
`loop.config.local.yaml` exists next to the config it first offers to create one: it lists the Linear team members from
|
|
54
|
+
Orca, asks whose queue this machine drains and, optionally, how much RAM to keep free and the worker ceiling, then
|
|
55
|
+
writes the gitignored overlay and reloads. It then runs the doctor and the automation-environment checks (harness and review CLIs on
|
|
56
|
+
PATH, `gh auth status`, checkout registered in Orca, queue owner), stops on any failed check unless `--force`,
|
|
57
|
+
offers a dry-run tick rehearsal (one orchestrator call, nothing written), lists the exact automations it will
|
|
58
|
+
create, and asks for confirmation before touching Orca. `--yes` accepts every prompt for scripted setups; without
|
|
59
|
+
a TTY the command refuses unless `--yes` or `--dry-run` is given; `--plain` keeps the old check-free behaviour.
|
|
60
|
+
|
|
61
|
+
It creates two automations in the Orca runtime, each bound to the main checkout as an existing workspace
|
|
62
|
+
with session reuse:
|
|
63
|
+
|
|
64
|
+
| Automation | Trigger | Precheck (plain command, exit 0 = run) | Prompt |
|
|
65
|
+
|---|---|---|---|
|
|
66
|
+
| `<prefix>-tick` | `schedule.tick` | `<harnessCommand> loop stage tick -f <config>` (runs the tick, exits 1) | never reached under `runner: precheck` |
|
|
67
|
+
| `<prefix>-deliver` | `schedule.deliver` | `<harnessCommand> loop stage deliver -f <config>` (runs deliver, exits 1) | never reached under `runner: precheck` |
|
|
68
|
+
|
|
69
|
+
With the default `schedule.runner: precheck` the **precheck command is the stage itself** (`ak-harness loop stage
|
|
70
|
+
tick|deliver`): it runs the harness, prints the JSON report and always exits 1, so Orca records every run as
|
|
71
|
+
`skipped_precheck` with the report in `precheckResult.stdout` and never opens an agent session. This is deliberate:
|
|
72
|
+
Orca caps a precheck at 600 s, so `contract.timeoutMs` (default 300 s) plus dispatch must fit one run; an Orca-launched agent starts in bypass-permissions mode and waits for a human to accept the warning, which leaks one
|
|
73
|
+
stuck session per run. `schedule.runner: agent` keeps the legacy behaviour for providers that run unattended.
|
|
74
|
+
Runs and their output are visible in Orca's Automations view and via `loop status`.
|
|
75
|
+
|
|
76
|
+
`schedule.harnessCommand` must resolve inside Orca's environment: install the harness globally
|
|
77
|
+
(`npm i -g @agentskit/harness`) or set an absolute command. `loop install` warns when it cannot find it on this shell's PATH.
|
|
78
|
+
|
|
79
|
+
Optional SessionStart hook for Claude Code (`.claude/settings.json` of the target project):
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{ "hooks": { "SessionStart": [{ "hooks": [{ "type": "command", "command": "ak-harness loop hook -f loop.config.yaml", "timeout": 10 }] }] } }
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
It prints `loop: installed (2/2, last run …)` or the install command; it never installs or changes anything.
|
|
86
|
+
|
|
87
|
+
## Deliver
|
|
88
|
+
|
|
89
|
+
For every issue the loop dispatched (`<stateDir>/issues/<id>/dispatch.json`) and has not finished:
|
|
90
|
+
|
|
91
|
+
| Situation | Action |
|
|
92
|
+
|---|---|
|
|
93
|
+
| No PR, worker terminal alive and active | wait |
|
|
94
|
+
| No PR, idle ≥ `workerIdleTimeoutMin` | one check-in via `terminal send`; idle again after that → **stuck**: lease released, issue → `returnState` + `blocked`, worktree kept |
|
|
95
|
+
| No PR, terminal gone (> 5 min after dispatch) | **stuck** as above |
|
|
96
|
+
| PR touches `selfEditPaths` | **held**: one PR comment, no review, no merge |
|
|
97
|
+
| PR conflicting | rebase instruction to the worker, once per head (does not count as a fix round) |
|
|
98
|
+
| CI red | failing check names to the worker; counts as a fix round |
|
|
99
|
+
| CI pending / required check missing | wait |
|
|
100
|
+
| CI green, head not reviewed | `agentskit-review --pr … --block <minSeverity> --result … [--post]` with the first available reviewer candidate |
|
|
101
|
+
| Review findings ≥ floor | findings to the worker; counts as a fix round; same head is never re-reviewed |
|
|
102
|
+
| Fix rounds exhausted (`maxFixRounds`) | **blocked**: Linear comment + label + `returnState`, PR comment, lease released, worktree and PR kept |
|
|
103
|
+
| Review clean, `merge.auto` | `gh api PUT …/merge` with `sha=<reviewed head>` (GitHub refuses if the head moved) → Linear attach + comment + `doneState`, worktree removed when `cleanupWorktree` |
|
|
104
|
+
| PR merged outside the loop | same completion path |
|
|
105
|
+
| PR closed without merge | **abandoned**: lease released, issue → `returnState`, worktree kept |
|
|
106
|
+
|
|
107
|
+
State lives in `<stateDir>/issues/<id>/delivery.json` (reviews per head, fix rounds, nudges) and every decision is
|
|
108
|
+
appended to `<stateDir>/events.ndjson`. `--dry-run` reports the decision for each issue without touching anything.
|
|
109
|
+
|
|
110
|
+
## One tick
|
|
111
|
+
|
|
112
|
+
1. **Intake** — `orca linear list-issues` once per configured state, filtered and ordered locally; issues already
|
|
113
|
+
leased, linked to a live worktree or sitting on their branch are *busy* and skipped.
|
|
114
|
+
2. **Admit** — `assessSlots` (machine) and the harness dispatch ledger (`<stateDir>/coordination`) decide how many
|
|
115
|
+
workers may start; a claim is atomic per issue/worktree/branch.
|
|
116
|
+
3. **Contract** — the orchestrator (first available candidate across `models.orchestrator` tiers) reads the issue and
|
|
117
|
+
the repository read-only and returns a JSON contract between `<<<LOOP_CONTRACT … LOOP_CONTRACT>>>`. Issue text is
|
|
118
|
+
wrapped as untrusted data. An auth/quota failure on one candidate marks it cooling down and the next is tried.
|
|
119
|
+
Contracts are cached under `<stateDir>/issues/<id>/contract.json` while the issue is unchanged.
|
|
120
|
+
4. **Dispatch or escalate** — a contract with at least one executable outcome and no blocking ambiguity becomes a
|
|
121
|
+
worker: `orca worktree create --linear-issue <url> --base-branch <base> --no-parent` (no `--agent`: Orca's agent
|
|
122
|
+
launcher runs Claude in bypass-permissions mode and waits for a human), then `orca terminal create --command
|
|
123
|
+
"<providers.<id>.tui>"`, `terminal wait --for tui-idle`, and the brief goes in through `terminal send`. The issue
|
|
124
|
+
moves to `In Progress` and one dedicated comment is posted. Otherwise the loop posts one
|
|
125
|
+
`needs-info` comment (deduped by contract digest), adds the label, and moves on without consuming a slot.
|
|
126
|
+
|
|
127
|
+
Every side effect is recorded in `<stateDir>/events.ndjson`; `dispatch.json` per issue links the worktree,
|
|
128
|
+
terminal handle, provider/model and lease for the deliver stage.
|
|
129
|
+
|
|
130
|
+
Start from [`loop.config.example.yaml`](../loop.config.example.yaml) at the package root.
|
|
131
|
+
|
|
132
|
+
## What the doctor checks
|
|
133
|
+
|
|
134
|
+
| Check | Source | Blocking |
|
|
135
|
+
|---|---|---|
|
|
136
|
+
| `orca.version` / `orca.runtime` | `orca --version`, `orca status --json` | yes — the loop cannot run without a reachable Orca runtime at or above `orca.minVersion` |
|
|
137
|
+
| `provider.<id>` | PATH lookup, `orca account list` usage windows, `orca agent hooks status`, env key names, optional probe, cooldown store | no — reported per provider |
|
|
138
|
+
| `routing.<role>` | tiers from `models.<role>` filtered by provider availability | yes — a role with no available provider blocks |
|
|
139
|
+
| `machine.slots` | `sampleMachine` + `adaptiveConcurrency`, free RAM reserve, WSL cap, running worktrees | no — 0 free slots is a warning, not a failure |
|
|
140
|
+
| `linear.queue` | `orca linear list-issues` per configured state, filtered and ordered locally | yes — an unreachable Linear blocks |
|
|
141
|
+
|
|
142
|
+
## Model routing
|
|
143
|
+
|
|
144
|
+
`models.<role>` is a list of tiers; each tier is a list of `provider/model`. Tiers are tried in order and, inside a
|
|
145
|
+
tier, providers in declaration order. The first provider that is **available** wins. A provider is available when
|
|
146
|
+
its binary is on PATH, its auth is not known to be missing, no Orca usage window is at or above
|
|
147
|
+
`cooldown.exhaustedPercent`, it is not cooling down, and its optional probe passed.
|
|
148
|
+
|
|
149
|
+
Providers authenticate through their own CLI login (`claude login`, `codex login`, `grok login`); only providers
|
|
150
|
+
declared `auth: api-key` need an environment variable, and the loop never reads its value. Orca has no per-run model flag; the chosen model is rendered into `providers.<id>.tui` (for example
|
|
151
|
+
`codex -m {model} --full-auto`) and launched in the worker terminal.
|
|
152
|
+
|
|
153
|
+
When a provider runs out of usage the loop records a cooldown in `<stateDir>/provider-cooldowns.json`:
|
|
154
|
+
`initialMin` doubling up to `maxMin`, never earlier than the reset instant Orca reported.
|
|
155
|
+
|
|
156
|
+
## Machine slots
|
|
157
|
+
|
|
158
|
+
`maxAgents = max(floor, min(adaptiveConcurrency(ceiling), ramBound, wslCap?))` where `ceiling` defaults to
|
|
159
|
+
`cpus / 2`, `ramBound` fits `agentRssMb` agents into free RAM minus `minFreeRamGb`, and the WSL cap applies only
|
|
160
|
+
inside a WSL distro (host Defender load is invisible there). The loop never lowers a running worker; it only
|
|
161
|
+
decides whether to start another.
|
|
162
|
+
|
|
163
|
+
## Integrations used by the loop
|
|
164
|
+
|
|
165
|
+
The loop talks to the rest of AgentsKit through **adapters and CLI seams**, not by importing those packages into
|
|
166
|
+
the published dependency tree. `@agentskit/harness` stays dependency-light (`commander`, `ink`, `react`, `yaml`,
|
|
167
|
+
`zod`); Doc Bridge and Code Review are optional at runtime.
|
|
168
|
+
|
|
169
|
+
### Doc Bridge (context for the orchestrator)
|
|
170
|
+
|
|
171
|
+
| Item | Detail |
|
|
172
|
+
|---|---|
|
|
173
|
+
| Adapter | `src/adapters/doc-bridge.ts` → `createDocBridgeContextProvider` |
|
|
174
|
+
| Loop wiring | `resolveDocContext` in `src/loop/contract.ts` |
|
|
175
|
+
| Trigger | `.doc-bridge/index.json` exists under `project.root` |
|
|
176
|
+
| Knob | `contract.maxContextReferences` (default `6`; `0` disables) |
|
|
177
|
+
| Behaviour | Query is `"<issue id> <title>"`. Up to N deterministic references are appended to the orchestrator prompt. Missing or malformed index → **no refs** (loop continues). |
|
|
178
|
+
| Boundary | No `@agentskit/doc-bridge` import; the adapter only reads the local index contract ([ADR-0003](ADR-0003-doc-bridge-context-binding.md)). Index build/refresh stays with Doc Bridge (`pnpm docs:bridge:index` in repos that use it). |
|
|
179
|
+
|
|
180
|
+
### Code Review (`agentskit-review`)
|
|
181
|
+
|
|
182
|
+
| Item | Detail |
|
|
183
|
+
|---|---|
|
|
184
|
+
| Adapter | `src/adapters/code-review.ts` → `runCodeReview` / `buildReviewArgv` |
|
|
185
|
+
| Loop wiring | Deliver stage, after CI is green and the head has not been reviewed |
|
|
186
|
+
| CLI | `delivery.review.cli` (default `agentskit-review` from `@agentskit/code-review`) |
|
|
187
|
+
| Knobs | `mode` (`trusted-local` recommended so CLI logins work), `transport` (`headless` for current Grok CLI), `profile` (`fast` fits a 600 s Orca stage; `full` needs batching), `votes`, `concurrency`, `minSeverity`, `deadlineMs`, `maxCalls`, `post` |
|
|
188
|
+
| Provider/model | First available candidate from `models.reviewer` tiers |
|
|
189
|
+
| Verdicts | exit `0` → clean (merge path); `1` → findings ≥ floor (fix round); `2` / timeout / incomplete → wait and retry |
|
|
190
|
+
| Boundary | Argv + `--result` file only; the harness never embeds the review SDK. |
|
|
191
|
+
|
|
192
|
+
### Eval battery (package quality, not the live loop)
|
|
193
|
+
|
|
194
|
+
`evals/manifest.json` plus `runEvalBattery` / `pnpm test:eval-battery` score harness components (`doc-bridge`,
|
|
195
|
+
`code-review`, `orca-worktree`, `memory`, …) under a frozen fixture provider. That is the **library** eval gate.
|
|
196
|
+
The live SDLC loop does **not** call the eval battery on every PR; it calls `agentskit-review` on each head.
|
|
197
|
+
|
|
198
|
+
Loop-focused Vitest coverage lives under `test/loop-*.test.ts`, `test/review.test.ts`, and `test/doc-bridge.test.ts`.
|
|
199
|
+
|
|
200
|
+
## AgentsKit ecosystem map (what the harness has vs what the loop uses)
|
|
201
|
+
|
|
202
|
+
Legend: **Loop** = wired into `ak-harness loop …` today · **Kernel** = public API / contracts available to callers ·
|
|
203
|
+
**Compat** = pinned in `compatibility/manifest.json` · **Absent** = no seam yet.
|
|
204
|
+
|
|
205
|
+
| Capability | Status | Where | Notes for SDLC |
|
|
206
|
+
|---|---|---|---|
|
|
207
|
+
| **Doc Bridge** | Loop + Kernel + Compat | `adapters/doc-bridge.ts`, contract stage | Optional context on contract freeze. Playbook/docs surfaces appear as Doc Bridge scopes when the index includes them. |
|
|
208
|
+
| **Code Review** | Loop + Compat | `adapters/code-review.ts`, deliver | Live adversarial review before auto-merge. |
|
|
209
|
+
| **Orca / Linear / GitHub** | Loop | `adapters/orca-cli.ts`, `linear-orca.ts`, `github-cli.ts` | Scheduler, worktrees, queue, PR merge. |
|
|
210
|
+
| **Coding-agent CLIs** | Loop | `adapters/providers.ts`, `models.*` tiers | Claude / Codex / Grok / OpenCode via TUI + headless templates — not an AgentsKit agent registry. |
|
|
211
|
+
| **Memory** | Loop + Kernel + Compat | `kernel/memory.ts`, `loop/memory.ts` | Approved learnings (`loop learning promote`) shrink Doc Bridge/issue text in contract + brief. |
|
|
212
|
+
| **Eval** | Kernel + Compat | `kernel/eval.ts`, `evals/manifest.json` | Battery + `assessAgentEval`. **Not run inside tick/deliver**. |
|
|
213
|
+
| **Runtime (process / Docker)** | Kernel | `execution/runtime.ts` | Tool runtimes with attestation for kernel/agent sessions. Loop workers run as Orca terminals + provider TUIs instead. |
|
|
214
|
+
| **Plugin / context registry** | Kernel | `kernel/plugins.ts`, `CONTEXT_PROVIDER_SLOT` | Typed slots so Doc Bridge / Playbook / custom providers plug in without kernel changes. Loop uses Doc Bridge directly today. |
|
|
215
|
+
| **Playbook practices** | Loop (via Doc Bridge scopes) | `contract.briefScopes` → worker brief | Titles/paths for `playbook` / `for-agents` scopes listed in the brief when indexed. |
|
|
216
|
+
| **RAG (`@agentskit/rag` / os-rag)** | Kernel adapter (opt-in) | `adapters/rag-context.ts` | Argv/`ContextProvider` seam; enable via `rag.enabled` + `contract.contextProviders`. No hard dep. |
|
|
217
|
+
| **AgentsKit agent registry** | Composition (opt-in file) | `loop/agent-registry.ts` | Optional `agents.registry.yaml` role→TUI/argv overlay. Not OS marketplace. |
|
|
218
|
+
| **MCP / event bridge** | Kernel adapter + ADR-0028 | `adapters/mcp.ts` | Policy-gated tool bridge; **not** wired into tick/deliver in 0.6.0. |
|
|
219
|
+
| **`@agentskit/core` / `@agentskit/eval` / `@agentskit/memory`** | Compat pins only | `compatibility/manifest.json` | Upstream packages are compatibility-tested; harness does **not** depend on them at runtime. Callers adapt them through the seams above. |
|
|
220
|
+
|
|
221
|
+
Compatibility report for 0.4.0 was **fail-closed** on code-review quality baselines and the no-Harness pilot cohort; see `compatibility/report.md`. Refresh after each release (qualification + pinned revisions).
|
|
222
|
+
|
|
223
|
+
## What can be added to help the SDLC
|
|
224
|
+
|
|
225
|
+
**0.6.0 ships the backlog below** (memory, doctor freshness/review probe, brief scopes, deliver smoke, agent registry, RAG provider, MCP seam+ADR, Docker verify config, weekly retro automation). Remaining work is dogfooding and deeper MCP/OS registry integrations.
|
|
226
|
+
|
|
227
|
+
Ordered by leverage for a keep-pushing loop (config/adapters first; no kernel redesign required for the early items).
|
|
228
|
+
|
|
229
|
+
| Priority | Addition | Why it helps | Suggested shape |
|
|
230
|
+
|---|---|---|---|
|
|
231
|
+
| P0 | **Memory in contract + brief** | Stop re-deriving the same repo facts; carry approved decisions across tickets | On contract freeze / worker brief, `recall` from an `AgentMemoryAdapter` (backed by `@agentskit/memory` or a file store under `<stateDir>`). Persist only human-`promoteLearnings` / retro-approved records. |
|
|
232
|
+
| P0 | **Doc Bridge freshness gate** | Orchestrator context goes stale when the index is old | Doctor check: index exists, `contentHash` age, optional `docs:bridge:index` hint when missing. |
|
|
233
|
+
| P1 | **Playbook / for-agents snippets in the brief** | Workers skip repo conventions that already exist as docs | Resolve Doc Bridge (or a Playbook `ContextProvider`) with scopes `playbook` + `for-agents` and render a bounded “must follow” block into `renderWorkerBrief`. |
|
|
234
|
+
| P1 | **Eval smoke on deliver (optional)** | Catch harness/component regressions before merge on harness itself | Config flag to run a **bounded** subset of `evals/manifest.json` (or project `ak-verify`) as an extra deliver gate — not a full battery on every product PR. |
|
|
235
|
+
| P1 | **Review transport/doctor** | Incomplete reviews burned the pilot (login / model id / stage budget) | Doctor probes `agentskit-review --help`, configured transport, and a one-lens trusted-local dry call; surface `review-tool-errors` in retro. |
|
|
236
|
+
| P2 | **RAG context provider** | Large codebases exceed Doc Bridge’s deterministic top-N | New adapter implementing `ContextProvider` over `@agentskit/rag` / os-rag; same freeze-into-contract rules as Doc Bridge (hash + cap). |
|
|
237
|
+
| P2 | **AgentsKit agent/skill registry** | Reuse named agents (reviewer, security, docs) instead of free-form CLI templates | Optional `agents.registry` file or OS dispatcher lookup → map role → argv/TUI. Keep fail-closed when the registry entry is missing. |
|
|
238
|
+
| P2 | **MCP tools behind policy** | Controlled access to issue trackers, browsers, internal APIs | MCP adapter + `createPolicyGate` allowlist; record hashed tool events. Requires ADR (MODULE-BOUNDARIES already flags this). |
|
|
239
|
+
| P3 | **Kernel runtime for untrusted tools** | Sandbox one-off scripts the worker must not run on the host | Offer Docker tool runtime as an opt-in for verify commands; loop default stays Orca worktree. |
|
|
240
|
+
| P3 | **Weekly Linear retro automation** | Close the continuous-improvement loop without a human remembering `loop retro` | Orca schedule → `loop retro --learnings` → comment on a fixed Linear issue (project vs harness sections already split). |
|
|
241
|
+
|
|
242
|
+
Non-goals for the loop: embedding LLM SDKs, reading API key values from config, or making `@agentskit/*` hard dependencies of the published package. New ecosystem pieces enter as adapters/plugins with argv/timeouts and eval coverage ([ADR-0026](ADR-0026-kernel-adapters-boundary.md), [ADR-0027](ADR-0027-keep-pushing-loop.md)).
|
|
243
|
+
|
|
244
|
+
## Boundaries
|
|
245
|
+
|
|
246
|
+
Adapters (`src/adapters/command.ts`, `orca-cli.ts`, `providers.ts`, `linear-orca.ts`) depend on kernel contracts
|
|
247
|
+
only and receive a `CommandRunner`; they never spawn a shell. Composition (`src/loop/*`) supplies the real
|
|
248
|
+
runner and wires adapters together. See `docs/MODULE-BOUNDARIES.md`.
|
|
249
|
+
|
|
250
|
+
## Security notes
|
|
251
|
+
|
|
252
|
+
- `loop.config.yaml` holds env variable **names**, never values.
|
|
253
|
+
- Every external call is argv-based with a timeout; `ok: false` envelopes fail closed.
|
|
254
|
+
- Linear text is data. Later phases render it into worker briefs inside delimiters and never execute it.
|
|
255
|
+
|
|
256
|
+
## Continuous improvement: `loop retro`
|
|
257
|
+
|
|
258
|
+
`ak-harness loop retro --since 7d` reads `<stateDir>/events.ndjson`, every `issues/<id>/{contract,dispatch,delivery}.json`,
|
|
259
|
+
`provider-cooldowns.json` and (unless `--no-orca`) the Orca run records of the two automations, and prints a Markdown
|
|
260
|
+
digest:
|
|
261
|
+
|
|
262
|
+
- **Numbers** — contracts frozen, escalation rate, dispatches by provider, merged/blocked/stuck/abandoned/in flight,
|
|
263
|
+
review outcomes, fix rounds, median dispatch→merge, cooldowns, Orca runs (idle/work/timed out, durations).
|
|
264
|
+
- **Problems** — escalation reasons grouped by shape, blocked/stuck/abandoned issues.
|
|
265
|
+
- **What worked** — merged issues with worker, lead time and fix rounds.
|
|
266
|
+
- **Adjustments — project** — rule-based suggestions about the target project, each with its evidence and the
|
|
267
|
+
`loop.config.yaml` knob to turn (`escalation-rate`, `review-floor`, `fix-rounds`, `stuck-workers`, `review-incomplete`,
|
|
268
|
+
`provider-cooldowns`, `idle-loop`, `lead-time`, or `steady`).
|
|
269
|
+
- **Adjustments — harness** — defects or limitations of the library itself, derived from events the loop only emits
|
|
270
|
+
when its own machinery misbehaved (`worker-relaunch`, `dispatch-failures`, `contract-failures`, `merge-refusals`,
|
|
271
|
+
`review-tool-errors`, `stage-timeout`), with a pointer to the harness issue tracker. `--target project|harness`
|
|
272
|
+
filters one side.
|
|
273
|
+
|
|
274
|
+
The headings follow the harness retro grammar, so `--learnings` prints `LearningRecord`s in `proposed` state; a human
|
|
275
|
+
promotes them with `promoteLearnings` (ADR-0019 keeps that decision human). The calibration loop is: read the digest →
|
|
276
|
+
change one knob in `loop.config.yaml` → next digest measures the effect.
|
|
@@ -9,7 +9,7 @@ does not claim that the proposed 0.4.0 boundary has already been accepted.
|
|
|
9
9
|
|
|
10
10
|
| Class | Meaning | Dependency rule |
|
|
11
11
|
| --- | --- | --- |
|
|
12
|
-
| Kernel | Deterministic contracts, state transitions, policy and metric projections | May use Node standard library and other kernel modules; must not import adapters, provider SDKs, CLI composition, or
|
|
12
|
+
| Kernel | Deterministic contracts, state transitions, policy and metric projections | May use Node standard library and other kernel modules; must not import adapters, provider SDKs, CLI composition, credentials, or UI libraries (`ink`/`react` are composition-only). |
|
|
13
13
|
| Execution support | Local process, filesystem, event, evidence, and run lifecycle plumbing | May depend on the kernel; must expose provenance and fail closed at trust boundaries. |
|
|
14
14
|
| Adapter | Provider-specific or external-system integration | May depend on kernel contracts; must not be imported by kernel modules. |
|
|
15
15
|
| Composition | Package and CLI entry points | May compose kernel, execution support, and adapters; consumers use `src/index.ts`. |
|
|
@@ -73,6 +73,30 @@ modules, not a provider dependency.
|
|
|
73
73
|
| `src/adapters/agent.ts` | Adapter | Structured coding-agent execution with bounded timeout and failure classification | `errors`, `resilience`, `adapter-contract` | Agent/provider callback supplied by caller |
|
|
74
74
|
| `src/adapters/orca.ts` | Adapter | Safe, idempotent Orca dispatch plan | `errors`, `hash`, `preflight` | Orca CLI arguments; no execution |
|
|
75
75
|
| `src/adapters/tracking.ts` | Adapter | Idempotent provider-neutral tracking transition | `errors`, `hash` | User-supplied Linear/GitHub/etc. handler |
|
|
76
|
+
| `src/adapters/command.ts` | Adapter | Shell-free command runner seam, PATH executable lookup, Orca JSON envelope parsing | stdlib | Command runner supplied by composition or tests |
|
|
77
|
+
| `src/adapters/orca-cli.ts` | Adapter | Typed `orca … --json` calls: version/status/account/agent hooks, worktree ps/create/set/rm, terminal list/send/wait/read, automations list/create/edit/remove/run | `errors`, `command` | Orca CLI via the injected runner |
|
|
78
|
+
| `src/adapters/providers.ts` | Adapter | Coding-agent CLI availability: binary, auth, Orca usage windows, exhaustion, cooldown, optional probe | `command` | PATH, env var names, `orca account list` payload |
|
|
79
|
+
| `src/adapters/linear-orca.ts` | Adapter | Linear queue via `orca linear list-issues`, issue detail, status/comment/label/attach writes with deterministic `--write-id`, `TrackingAdapter` over Orca | `errors`, `hash`, `orca-cli`, `tracking`, `command` | Linear through the Orca CLI |
|
|
80
|
+
| `src/adapters/github-cli.ts` | Adapter | Pull request snapshots, check classification, self-edit path guard, optimistic squash-merge and comments via `gh` | `errors`, `command` | GitHub through the `gh` CLI |
|
|
81
|
+
| `src/adapters/code-review.ts` | Adapter | `agentskit-review` argv, `--result` parsing, severity floor, worker-facing findings | `command` (type-only) | AgentsKit code review CLI via runner |
|
|
82
|
+
| `src/loop/config.ts` | Composition | `loop.config.yaml` schema (zod), loading, model reference parsing | `errors`, `hash`, `model-policy`, `yaml`, `zod` | Project config file |
|
|
83
|
+
| `src/loop/process.ts` | Composition | Real shell-free `CommandRunner` with timeout and output caps | stdlib, `command` (type-only) | Child processes |
|
|
84
|
+
| `src/loop/slots.ts` | Composition | Machine slot assessment: adaptive concurrency, RAM reserve, WSL cap, floor | stdlib, `machine`, `config` | Host CPU/memory |
|
|
85
|
+
| `src/loop/routing.ts` | Composition | Tiered role → provider/model selection over provider availability | `model-policy`, `providers` (type-only), `config` | None |
|
|
86
|
+
| `src/loop/cooldown.ts` | Composition | Provider cooldown store with exponential backoff | stdlib, `providers` | `<stateDir>/provider-cooldowns.json` |
|
|
87
|
+
| `src/loop/doctor.ts` | Composition | Loop readiness report: Orca, providers, routing, slots, workers, queue | adapters, `config`, `cooldown`, `routing`, `slots` | Orca CLI via runner |
|
|
88
|
+
| `src/loop/contract.ts` | Composition | Task contract schema, orchestrator prompt (issue text as untrusted data), marked-JSON parsing, dispatchability assessment, candidate fallback with auth/quota classification, contract cache | `errors`, `hash`, `resilience`, `doc-bridge`, `config`, `routing` (type-only), `zod` | Headless coding-agent CLI via runner |
|
|
89
|
+
| `src/loop/brief.ts` | Composition | Worker prompt: frozen contract + repository rules + protected paths + done signal | `contract`, `config`, `linear-orca` (type-only) | None |
|
|
90
|
+
| `src/loop/tick.ts` | Composition | One keep-pushing tick: intake, admit (slots + dispatch ledger claim), contract, dispatch into an Orca worktree, Linear transition, escalation, precheck | adapters, `coordination`, `errors`, `hash`, `brief`, `config`, `contract`, `cooldown`, `doctor`, `routing`, `slots` | Orca CLI + Linear via runner; `<stateDir>` files |
|
|
91
|
+
| `src/loop/deliver.ts` | Composition | Deliver stage per dispatched issue: PR detection, self-edit hold, conflict/CI/review fix rounds via terminal, review at head, optimistic squash-merge, Linear Done, cleanup, stuck/abandoned escalation | adapters, `coordination`, `errors`, `config`, `cooldown`, `doctor`, `routing`, `tick` | Orca, Linear, GitHub, agentskit-review via runner; `<stateDir>` files |
|
|
92
|
+
| `src/loop/install.ts` | Composition | Orca automation specs (`<prefix>-tick`, `<prefix>-deliver`) with read-only prechecks, idempotent create/edit by name, uninstall, status and the SessionStart hook line | `command`, `orca-cli`, `providers`, `errors`, `config`, `cooldown`, `doctor`, `routing` | Orca automations via runner |
|
|
93
|
+
| `src/loop/guided-install.ts` | Composition | Interactive install: doctor + environment preflight, dry-run rehearsal, confirmation, install, status; readline IO injected | `command`, `orca-cli`, `config`, `doctor`, `install`, `tick`, stdlib readline | Terminal prompts; Orca via runner |
|
|
94
|
+
| `src/loop/local-config.ts` | Composition | Per-machine overlay wizard: Linear team members via Orca, queue owner and machine tuning answers, YAML rendering and reload | `orca-cli`, `config`, `yaml` | Orca via runner; writes `loop.config.local.yaml` |
|
|
95
|
+
| `src/loop/retro.ts` | Composition | Retro digest over `events.ndjson`, per-issue state, cooldowns and Orca runs; rule-based calibration suggestions; Markdown that `parseRetro` can lift into learnings | `orca-cli`, `hash`, `learning`, `config`, `contract`, `cooldown`, `deliver`, `install`, `tick` | Orca via runner (optional); `<stateDir>` files |
|
|
96
|
+
| `src/loop/debrief.ts` | Composition | Human-facing read-only snapshot of what the loop is working on (in-flight, holds, escalations, cooldowns) | `config`, `contract`, `cooldown`, `deliver`, `retro`, `tick` | `<stateDir>` files only |
|
|
97
|
+
| `src/loop/watch.ts` | Composition | Poll delivery (+ optional live PR) and emit DONE/FAILED/ACTION_REQUIRED/PROGRESS for agents or humans | `command`, `github-cli`, `config`, `deliver`, `tick` | optional `gh` via runner; `<stateDir>` files |
|
|
98
|
+
| `src/loop/ui/components.tsx` | Composition | Ink components: check rows, sections, banner, spinner, select/confirm/text prompts | `ink`, `react`, `doctor` (type-only) | Terminal |
|
|
99
|
+
| `src/loop/ui/terminal.tsx` | Composition | `createRichIO`: Ink-backed IO for TTYs with a plain-text fallback | `ink`, `react`, `components`, `guided-install` (type-only) | Terminal |
|
|
76
100
|
|
|
77
101
|
## Allowed dependency directions and exceptions
|
|
78
102
|
|
|
@@ -125,16 +149,25 @@ Orca, and tracking. No adapter implementation is re-exported wholesale.
|
|
|
125
149
|
|
|
126
150
|
## External integration inventory
|
|
127
151
|
|
|
128
|
-
|
|
152
|
+
How these seams are wired into the keep-pushing loop (and what is still only a kernel contract) is summarized in
|
|
153
|
+
[`LOOP.md`](LOOP.md#integrations-used-by-the-loop) and the [AgentsKit ecosystem map](LOOP.md#agentskit-ecosystem-map-what-the-harness-has-vs-what-the-loop-uses).
|
|
154
|
+
|
|
155
|
+
| Integration | Current location | Side effects | Boundary |
|
|
129
156
|
| --- | --- | --- | --- |
|
|
130
157
|
| Doc Bridge | `src/adapters/doc-bridge.ts` | Reads a local index | Keep behind `ContextProvider`; measure context hit/quality separately. |
|
|
131
158
|
| Orca | `src/adapters/orca.ts` | None; produces argv and lifecycle projections only | Keep lease/worktree/issue-lock/SHA planning provider-neutral; execution belongs to the orchestrator. |
|
|
132
159
|
| Linear/GitHub/other tracker | `src/adapters/tracking.ts` callback | Caller-owned network mutation | Require idempotency key and explicit tracking authorization. |
|
|
160
|
+
| Orca CLI (loop) | `src/adapters/orca-cli.ts`, `src/adapters/linear-orca.ts` via `CommandRunner` | Read-only `--json` calls in the doctor; dispatch/mutation arrive in later loop phases | Argv only, never a shell string; every call bounded by a timeout; envelope `ok:false` fails closed. |
|
|
161
|
+
| Coding-agent CLIs | `src/adapters/providers.ts` | PATH lookup and optional probe command | Env keys are names only; usage comes from Orca, never from provider SDKs. |
|
|
162
|
+
| GitHub | `src/adapters/github-cli.ts` via `CommandRunner` | `gh pr view/list`, `gh api PUT …/merge` with `sha=<reviewed head>`, `gh pr comment` | Merge is refused by GitHub when the head moved; every call argv-based and bounded. |
|
|
163
|
+
| AgentsKit code review | `src/adapters/code-review.ts` via `CommandRunner` | `agentskit-review --pr … --result <file> [--post]` | Exit codes 0/1/2 plus the private result file decide clean/findings/incomplete; the floor is `--block`. |
|
|
133
164
|
| Process runtime | `src/execution/runtime.ts` | Starts child processes | Execution support; policy and evidence gates remain kernel decisions. |
|
|
134
165
|
| Docker runtime | `src/execution/runtime.ts` | Starts Docker containers | Optional sandbox selected by config, never a mandatory kernel dependency. |
|
|
135
166
|
| LLM provider/model | Caller/plugin | Provider call and token spend | Bind provider/model in experiment metadata; do not embed SDKs in kernel. |
|
|
136
|
-
| Memory backend | Caller/plugin; `memory.ts`
|
|
137
|
-
|
|
|
167
|
+
| Memory backend | Caller/plugin; `memory.ts` + `loop/memory.ts` | Backend reads/writes; loop file store under `stateDir` | Only human-promoted approved records enter loop prompts; prefer-over-DocBridge shrinks tokens. |
|
|
168
|
+
| RAG context | `src/adapters/rag-context.ts` | Optional argv / injected query | No hard `@agentskit/rag` dep; same ContextProvider freeze rules as Doc Bridge. |
|
|
169
|
+
| Agent registry (file) | `src/loop/agent-registry.ts` | Reads YAML | Role→TUI/argv overlay; fail closed only when `agents.requireRegistry`. |
|
|
170
|
+
| MCP/event bridge | `src/adapters/mcp.ts` + [ADR-0028](ADR-0028-mcp-adapter-boundary.md) | Policy-gated tool calls | Adapter-only in 0.6.0; **not** wired into tick/deliver. |
|
|
138
171
|
|
|
139
172
|
## Review status
|
|
140
173
|
|