@allocator-one/harness-cli 1.15.1 → 1.16.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
@@ -196,7 +196,13 @@ wait conditions, `Waiting:` says how many still hold it, and a
196
196
  `Wait conditions:` section lists each one (`[ ] gate "Finance sign-off" · <id>`,
197
197
  `[ ] gate "Compliance sign-off" [compliance] owned by Compliance officer (role:compliance_officer) · <id>`,
198
198
  `[x] not before … (satisfied …)`, `system event`) with the key and id
199
- `harness gate satisfy` takes.
199
+ `harness gate satisfy` takes. An issue that belongs to a plan gets a
200
+ `Plan:` line naming the plan by its root identifier, which the `plan`
201
+ commands take, then its status, the revision it runs, and whether that
202
+ revision lists the issue (`Plan: FR-1 · released · revision 8 · not in revision`,
203
+ with `Operator step` for a step Operator runs). `--json` carries the same as
204
+ `plan` (`{id, root, status, held, revision, in_revision, executor}`, or
205
+ `null`).
200
206
  `harness activity <id>` prints the issue's activity timeline: comments,
201
207
  creation, state and assignee changes, wait-condition events
202
208
  (`Ada satisfied the gate "Finance sign-off"`), and field changes
@@ -239,12 +245,18 @@ harness create --title "Fix login redirect" --type bug --priority high \
239
245
 
240
246
  - `--claim`: atomic. It assigns you and moves the issue to the team's first
241
247
  started state. A conflict (exit `1`, HTTP 409) names its reason: someone
242
- else holds the issue, or it is not claimable yet. Two reasons come with a
243
- next step: `agent_step` (Operator runs it; to do it yourself, set its
244
- executor to `none` with `harness plan edit <plan-id>` and release the plan
245
- again) and `waiting_on_condition` (`harness show` lists what it waits on;
246
- tick a gate with `harness gate satisfy`). It cannot be combined with
247
- `--assignee`.
248
+ else holds the issue, or it is not claimable yet. Some reasons come with a
249
+ next step. `agent_step`: a person can't claim an Operator step; to do it
250
+ yourself, set its executor to `none` with `harness plan edit <plan>` and
251
+ release the plan again. `plan_not_released`, `not_in_plan_revision` and
252
+ `edited_since_release`: when the server names the one plan governing the
253
+ issue as the one to release, the error ends with the command
254
+ (`run harness plan release FR-1`). When several plans govern it, the
255
+ server names none as the one to release, and the error names the nearest
256
+ to look at instead (`harness plan show FR-1`). A completed plan, or a
257
+ server that does not name the plan, gets no such hint. `waiting_on_condition`:
258
+ `harness show` lists what it waits on; tick a gate with
259
+ `harness gate satisfy`. It cannot be combined with `--assignee`.
248
260
  - `--state <name-or-type>`: moves the issue to the workflow state whose name
249
261
  or type matches.
250
262
  - `--title`, `--description`, `--design`, `--acceptance`, `--priority`,
@@ -355,12 +367,33 @@ nothing runs until a person releases one.
355
367
 
356
368
  ```sh
357
369
  harness plan create --file plan.yaml --team IO --idempotency-key q3-report
358
- harness plan show <plan-id>
359
- harness plan release <plan-id> --collaborator grace@example.com
370
+ harness plan list --team IO # the team's plans, by root
371
+ harness plan show IO-120 # by its root issue, or its id
372
+ harness plan release IO-120 --collaborator grace@example.com
360
373
  harness gate satisfy IO-121 "Finance sign-off"
361
374
  harness gate satisfy IO-121 compliance # by the gate's key
362
375
  ```
363
376
 
377
+ **Finding a plan.** Every plan command takes the plan's id or its root
378
+ issue's identifier (`FR-1`, in any casing). A step's identifier does not
379
+ open its plan: `harness show <issue>` names the plan an issue belongs to by
380
+ its root. `harness plan list` lists a team's plans, newest first, with
381
+ their root, status, whether they are held, the revision they run (`-`
382
+ before the first release) and their title:
383
+
384
+ ```text
385
+ ROOT STATUS HELD REVISION TITLE
386
+ FR-1 released no 8 Format radar
387
+ FR-200 held yes - Next quarter
388
+ ```
389
+
390
+ It takes `--team` (or `HARNESS_TEAM` or the repo config), `--status`
391
+ (`held`, `released`, `running`, `completed` or `needs_attention`) and
392
+ `--limit` (default 50, at most 100). There are no pages: when a list comes
393
+ back full, a stderr notice says older plans may exist. `--json` is the
394
+ server's list unchanged, each plan with its `id`, `root`, `title`,
395
+ `status`, `held`, `revision`, `released_at` and `inserted_at`.
396
+
364
397
  **The plan file** is the API's request body, as JSON (`.json`) or YAML
365
398
  (anything else, and stdin with `--file -`). YAML is read as YAML 1.2 and
366
399
  held to what JSON can carry: dates stay strings, and a duplicate key, an
@@ -415,7 +448,10 @@ steps:
415
448
  email). Only the owner can tick an owned gate. You can't name yourself as
416
449
  an owner, and that includes a role you hold. `owner: null` or no owner
417
450
  leaves the gate unowned.
418
- - A plan has at most 100 steps, its root included.
451
+ - A plan has at most the organization's max plan steps, its root included:
452
+ 1,000 unless a Harness admin changed it in Harness settings → Plans, and
453
+ never more than 2,000. Separately, it has at most 100 Operator steps,
454
+ the fixed limit of the delegated grant Operator runs them under.
419
455
  - `--team` (or `HARNESS_TEAM` or the repo config) is the root's team and the
420
456
  default team for people's steps. `--idempotency-key` works as it does for
421
457
  `create`: if a create times out, run it again with the same key to get
@@ -431,6 +467,18 @@ harness: The plan is not valid; nothing was changed (HTTP 422)
431
467
  plan: A plan with Operator steps needs a positive spend budget [spend_budget_required]
432
468
  ```
433
469
 
470
+ A plan over a step cap gets `too_many_steps`, once for each cap it is
471
+ over, and the line says which cap it is and whether anyone can raise it
472
+ (on create the root has no identifier yet, so the line starts `plan:`):
473
+
474
+ ```text
475
+ FR-1: the plan has 1203 steps, above this organization's max plan steps (1000): a Harness admin can raise "Max plan steps" in Harness settings → Plans (max_plan_steps, up to 2000) [too_many_steps]
476
+ FR-1: the plan has 103 Operator steps, above the fixed limit of 100: Operator's delegated grant caps a plan's agent steps, and no setting raises it — hand some to people (executor none) or split the plan [too_many_steps]
477
+ ```
478
+
479
+ The same applies to `plan edit` and `plan release`, which check the caps
480
+ again, and to the MCP tools' error text.
481
+
434
482
  A gate's owner is checked the same way. The owner violations are
435
483
  `invalid_owner`, `unknown_role`, `unknown_owner`, `owner_is_member`,
436
484
  `owner_is_actor` (you named yourself), `owner_not_allowed` (an owner on a
@@ -438,10 +486,11 @@ condition that is not a gate), `expert_owner_requires_plan`, and
438
486
  `duplicate_gate_key`. A `gate:` that conflicts with the condition's `kind`
439
487
  or `key` is `invalid_condition`.
440
488
 
441
- **Show.** `harness plan show <plan-id>` prints the plan's status, budgets,
489
+ **Show.** `harness plan show <plan>` prints the plan's status, budgets,
442
490
  revision, and spend estimate, then every step in tree order (indented by
443
491
  depth) with its key, executor, state, and status. The status is `ready`,
444
- `held` (edited since the release), `not in revision` (added after it),
492
+ `held` (an Operator step changed since the release, which waits for the
493
+ next one; a person's changed step stays `ready`), `not in revision` (added after it),
445
494
  `waiting` (on a wait condition), `container`, `done`, `cancelled`,
446
495
  `archived`, or `-`. The edges and each step's wait conditions come after
447
496
  the steps. Each gate shows its key and owner. A `Waiting for:` section then
@@ -465,7 +514,7 @@ email), or an outside expert by email (`val@example.com (expert)`).
465
514
  `[]` when nobody can tick, `null` for an unowned gate or when the holders
466
515
  are not known).
467
516
 
468
- **Edit.** `harness plan edit <plan-id> --file edits.yaml` changes step
517
+ **Edit.** `harness plan edit <plan> --file edits.yaml` changes step
469
518
  executors and keys, naming each step by its `step` key or `issue`
470
519
  identifier, and the budgets (`retry_budget`, `spend_budget_cents`):
471
520
 
@@ -475,33 +524,38 @@ steps:
475
524
  executor: none # hand the step to a person
476
525
  ```
477
526
 
478
- Editing a released step holds it until the plan is released again. A
479
- budget change needs the plan held first. Descriptions, parents, and edges
527
+ Editing a released Operator step, or handing one to a person, holds it
528
+ until the plan is released again. A person's step stays workable, and the
529
+ next release takes the change in; until then the plan lists every changed
530
+ step under `Changed since the release:`. A budget change needs the plan
531
+ held first. Descriptions, parents, and edges
480
532
  are edited with the issue commands (`update`, `dep`). Conditions are set
481
533
  when the plan is created. Editing them later goes through the API's issue
482
534
  condition endpoints, which have no command yet; `gate satisfy` ticks a
483
535
  gate.
484
536
 
485
- **Release and hold.** `harness plan release <plan-id>` releases the plan as
486
- you: it freezes the next revision and lets ready steps run.
537
+ **Release and hold.** `harness plan release <plan>` releases the plan as
538
+ you: it freezes the next revision, which takes in the steps added or edited
539
+ since the last one, and lets ready steps run.
487
540
  `--collaborator <id-or-email>` (repeatable) adds people to the plan room
488
541
  where its Operator steps run, and `--retry-budget` and
489
542
  `--spend-budget-cents` set the budgets. Each Operator step runs as a job
490
543
  (`harness jobs` names its plan step), and the changes a job proposes need a
491
544
  person's approval in the app, at the job's approval link. The CLI never
492
- approves. `harness plan hold <plan-id>` pauses every step until the plan is
545
+ approves. `harness plan hold <plan>` pauses every step until the plan is
493
546
  released again.
494
547
 
495
548
  **Gates.** `harness gate satisfy <issue> <gate>` ticks a gate and
496
549
  `harness gate unsatisfy <issue> <gate>` unticks it. `<gate>` is the gate's
497
- key, its label, or its condition id, all shown by `harness show`. None of
498
- the three outranks the others: when `<gate>` exactly matches more than one
499
- condition, say one gate's key and another gate's label, the command
500
- refuses and lists each one's id, key, and label instead of choosing. Pass
501
- the condition id of the one you mean. Only when nothing matches exactly
502
- does a label or key match ignoring case, and that too is refused when more
503
- than one gate matches. Ticking a gate requires staff standing in the
504
- organization or a place in its plan's room. The server refuses an
550
+ key, its label, or its condition id, all shown by `harness show`. A condition
551
+ UUID writes directly without listing conditions, so a non-staff gate owner can
552
+ reach the server's write authorization. A UUID always addresses that condition,
553
+ even if another gate uses it as its key or label. Keys and labels require the
554
+ staff-only lookup; a denied lookup explains how to use a condition id instead.
555
+ When a name matches multiple gates, the command lists their ids instead of
556
+ choosing. Only when nothing matches exactly does a label or key match ignoring
557
+ case, and that too is refused when more than one gate matches. Ticking a gate
558
+ requires staff standing in the organization or a place in its plan's room. The server refuses an
505
559
  Operator-only login (`operator-cli`) here, even for a person in the plan's
506
560
  room: it reaches only the Operator commands, `whoami` and `logout`. Only
507
561
  the owner can tick an owned gate, and only its owner or Harness staff can
@@ -513,8 +567,10 @@ harness: Cannot satisfy gate "Compliance sign-off" on IO-121: only its owner, Co
513
567
  ```
514
568
 
515
569
  A gate with no owner by then gets the same error without a name. Against
516
- a server that does not send the owner, the command reads the conditions
517
- again to find it.
570
+ a server that does not send the owner, a key or label write reads the conditions
571
+ again to find it. A direct condition-id write never lists conditions, including
572
+ on errors, and leaves the owner unnamed if the refusal does not name one.
573
+ Direct writes also make no claim about other conditions still holding the issue.
518
574
 
519
575
  **Conditions.** `harness conditions <issue>` lists an issue's wait
520
576
  conditions, oldest first, one per line as `show` lists them: each one's
@@ -522,7 +578,9 @@ box, what it waits for (a gate's label, key and owner), when and by whom it
522
578
  was satisfied, and its id. `--json` is the list as the server sends it.
523
579
 
524
580
  A server without the plan API answers the plan commands with a 404, and the
525
- error says that the server may predate plans.
581
+ error says that the server may predate plans. A root identifier that opens
582
+ no plan is the same 404 as an unknown id, and the error says how to find
583
+ the plan an issue belongs to.
526
584
 
527
585
  ## Outside experts
528
586
 
@@ -942,6 +1000,31 @@ Login tokens have it; `aone_` tokens need to be minted with it. There is
942
1000
  deliberately no MCP tool for keys, because a tool result is text the model
943
1001
  can read.
944
1002
 
1003
+ ## Review gate
1004
+
1005
+ A pull request merges only once its enforced Review Council gate, the
1006
+ attested review a gate workflow runs for its head, has converged. When that
1007
+ gate sits at `unverified`, these commands say why and recover it:
1008
+
1009
+ - `harness review status <pr>` prints the enforced and advisory status, the
1010
+ head's gate check, and a failed or timed-out latest attempt with its reason,
1011
+ whether its evidence was recorded, and what comes next. Next is either an
1012
+ automatic retry by Harness or a retry you request. `--json` returns the gate
1013
+ status as the server sends it.
1014
+ - `harness review retry <pr> [--reason <text>]` retries the latest attempt of
1015
+ the current head's gate check. It reads the head, the check and the attempt
1016
+ from the gate status, so you name only the pull request, and prints the new
1017
+ attempt (`--json`: `{attempt, outcome}`). Running it again for the same
1018
+ attempt returns the attempt already queued rather than paying for another
1019
+ review run. It needs a login with `reviews:write`. It refuses, saying why,
1020
+ while the attempt is still running, while Harness is retrying it itself, or
1021
+ when the head's advisory review has not converged.
1022
+
1023
+ `<pr>` is `owner/repo#<number>`, the pull request URL, or a bare number read
1024
+ against `--repo owner/repo` or this checkout's GitHub `origin`. Never dispatch
1025
+ the gate workflow by hand instead: a run without a registered attempt cannot
1026
+ approve the head.
1027
+
945
1028
  ## Scripting contract
946
1029
 
947
1030
  - **`--json` on every command** except `mcp`. It replaces the human output
@@ -999,7 +1082,7 @@ command instead of the `npx` form. Any other MCP client can use the same command
999
1082
  { "mcpServers": { "harness": { "command": "npx", "args": ["-y", "@allocator-one/harness-cli", "mcp"] } } }
1000
1083
  ```
1001
1084
 
1002
- The server exposes 72 tools:
1085
+ The server exposes 74 tools:
1003
1086
 
1004
1087
  | Area | Tools |
1005
1088
  | --- | --- |
@@ -1011,7 +1094,7 @@ The server exposes 72 tools:
1011
1094
  | Labels | `label_list`, `label_create`, `label_update`, `label_delete` |
1012
1095
  | Teams and states | `team_list`, `team_create`, `team_rename`, `team_set_default`, `workflow_states`, `state_add`, `state_update`, `state_order`, `state_delete` |
1013
1096
  | People | `member_list`, `member_add`, `member_set_role`, `user_list` |
1014
- | Plans and gates | `plan_create`, `plan_show`, `plan_edit`, `plan_release`, `plan_hold`, `gate_set`, `condition_list` |
1097
+ | Plans and gates | `plan_list`, `plan_create`, `plan_show`, `plan_edit`, `plan_release`, `plan_hold`, `gate_set`, `condition_list` |
1015
1098
  | Outside experts | `assignment_list` |
1016
1099
  | Operator jobs | `jobs_list`, `job_show`, `job_changes`, `job_start`, `job_steer`, `job_cancel`, `job_pause` |
1017
1100
  | Continue and procedures | `job_continue`, `procedure_save`, `procedure_show`, `procedure_run` |
@@ -1040,7 +1123,9 @@ Some tools behave differently from their commands:
1040
1123
  `steps`, `retry_budget`, and `spend_budget_cents` directly. As with every
1041
1124
  tool, a top-level argument the tool does not declare is dropped.
1042
1125
  `gate_set` takes `issue`, `gate` (a key, label, or condition id), and
1043
- `satisfied`.
1126
+ `satisfied`. The plan tools' `id` is the plan's id or its root issue's
1127
+ identifier, as for the commands; `plan_list` takes `team`, `status` and
1128
+ `limit`, and `issue_show` carries the issue's `plan`.
1044
1129
  - An API error's details come back in the tool error text: a validation
1045
1130
  error's fields, and an invalid plan's violations, one per line by step
1046
1131
  key.
@@ -1100,16 +1185,32 @@ directory the way git finds `.git`, gives every clone of a repo the same
1100
1185
  defaults:
1101
1186
 
1102
1187
  ```json
1103
- { "team": "CLI" }
1188
+ { "team": "CLI", "org": "3f96a9c0-1584-4c65-9c4b-056055024bc9" }
1104
1189
  ```
1105
1190
 
1106
1191
  | Field | Effect |
1107
1192
  | --- | --- |
1108
1193
  | `team` | Default team key. Precedence: `--team`, then `HARNESS_TEAM`, then the repo config. |
1109
1194
  | `url` | Target host. `HARNESS_API_URL` takes precedence. Before an automatic login opens a browser at a host that only the repo names, the CLI asks for confirmation, once per host. |
1110
- | `org` | Reserved. It is parsed but has no effect yet. |
1111
-
1112
- A malformed file is ignored with a warning on stderr.
1195
+ | `org` | Organization UUID selecting an org-bound login. Login verifies the server-reported org before storing it. The org never derives a hostname or becomes an API header. |
1196
+
1197
+ A malformed file is ignored with a warning on stderr. An invalid org UUID
1198
+ refuses the command. With `org`, the host defaults to `https://harness.infra.one`
1199
+ unless `url` or `HARNESS_API_URL` specifies it. The repo-selected host passes
1200
+ the same once-per-host trust prompt as a repo `url` before browser login.
1201
+
1202
+ Sign in once with `harness login` from the repo and select its organization
1203
+ on the page. Org logins use separate host-and-org-keyed credential files,
1204
+ so logging into one org does not overwrite or revoke another org's login.
1205
+ The legacy `credentials.json` remains unchanged and is used by repos without
1206
+ `org`. When adding `org` to an existing repo, log in again for that org; the
1207
+ legacy credential is not assumed to belong to it. `logout` revokes and
1208
+ forgets only the selected login. Explicit `HARNESS_API_TOKEN` credentials
1209
+ override org selection; their authority remains whatever the server minted.
1210
+ An org-specific login accepts only a credential whose session describes that
1211
+ organization. Outside-expert `pxc_` credentials have no org description, so
1212
+ use them from a repo without `org` or pass them explicitly through
1213
+ `HARNESS_API_TOKEN`.
1113
1214
 
1114
1215
  ### Hosts and tokens
1115
1216
 
@@ -1123,13 +1224,14 @@ refuses with exit code 2 instead of sending the token there. Set
1123
1224
  `HARNESS_API_URL` explicitly if you do mean that host. Without
1124
1225
  `HARNESS_API_TOKEN`, a repo-named host needs a login of its own, and the
1125
1226
  automatic login asks for confirmation first, as described above. Plain
1126
- `http://` is accepted only for localhost.
1227
+ `http://` is accepted only for `localhost`, any `*.localhost` host (such as
1228
+ a local `harness.infraone.localhost` dev server), `127.0.0.1` and `[::1]`.
1127
1229
 
1128
1230
  ### Environment variables
1129
1231
 
1130
1232
  | Variable | Effect |
1131
1233
  | --- | --- |
1132
- | `HARNESS_API_URL` | Target host (https, or http against localhost only). |
1234
+ | `HARNESS_API_URL` | Target host (https, or http against `localhost`, `*.localhost`, `127.0.0.1` or `[::1]` only). |
1133
1235
  | `HARNESS_API_TOKEN` | An `aone_…` API token, or an outside expert's `pxc_…` credential. It takes precedence over the stored login. Headless use only. |
1134
1236
  | `HARNESS_ACTOR` | Write attribution, sent only when set. Without it the server attributes writes to the signed-in user, or for `aone_` tokens to the token's name. Headless use only. |
1135
1237
  | `HARNESS_TEAM` | Default team key for commands that take `--team`. |
@@ -1143,6 +1245,7 @@ automatic login asks for confirmation first, as described above. Plain
1143
1245
 
1144
1246
  | Path | Contents |
1145
1247
  | --- | --- |
1248
+ | `~/.config/harness/credentials-org-<hash>.json` | A server-verified org login, keyed by host and org UUID, mode 0600; same `{url, token}` format. |
1146
1249
  | `~/.config/harness/credentials.json` | The stored login: one `{url, token}` pair, mode 0600. |
1147
1250
  | `~/.config/harness/trusted-hosts.json` | Repo-config hosts you agreed to log in to. |
1148
1251
  | `~/.cache/harness/attachments/` | Images downloaded by `show` (or `HARNESS_CACHE_DIR`). |