Skip to content

Commit 14df595

Browse files
committed
feat(init): one .agents row that names the detected harnesses
The picker offered .agents twice, as Codex and as Agent Skills, so a Codex user would see their harness. It now offers one .agents row labelled with the detected harnesses that read .agents/skills, in catalog order ("OpenCode, Codex, and other .agents harnesses"), naming all of them when none is detected. Gemini CLI and Crush are detected and install into .agents. OpenCode is named but does not pre-check .agents, since it already gets .opencode. Archives the agents-row-names-harnesses OpenSpec change.
1 parent 5439e1c commit 14df595

10 files changed

Lines changed: 329 additions & 174 deletions

File tree

‎.changeset/pinned-cli-permissions.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ Released builds now pin their own version. The installed skill and the `agent` r
77
`init` now also reports stale Taskless pins in CI and git-hook files (GitHub Actions, GitLab CI, CircleCI, husky, lefthook, pre-commit, and the rest of the files `detect` recognizes) by file and line, through the same notice and `pinnedCli` JSON field as `package.json` pins. It recommends the version to move to and never edits the file.
88

99
`init` now also allows exactly the installed CLI in each agent it installs for, so a harness that gates download-and-run commands lets Taskless through without a prompt: Claude Code (`.claude/settings.json`), Cursor (`.cursor/permissions.json` and `.cursor/cli.json`), OpenCode (`opencode.json[c]`), and Codex (`.codex/rules/taskless.rules`, when Codex is present). Each rule names one version and cannot match another. Every edit is announced, as `Edited <file>` with a green `ALLOW:` line, and the wizard shows it and asks before writing. An upgrade replaces only the rule Taskless recorded, a rule you wrote is never touched, and a file that denies the command or does not parse is left alone and reported. `init --json` carries the same edits under `permissions`. Agents Taskless does not install into use per-command approval through the skill.
10+
11+
The setup wizard's tool list now has one `.agents/` row, labelled with the detected harnesses that read it, such as `OpenCode, Codex, and other .agents harnesses (.agents/)`, instead of separate `Codex` and `Agent Skills` rows. Gemini CLI and Crush are now detected, and install the skill into `.agents/`.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
## Why
2+
3+
The wizard's tool picker offers `.agents/` twice: as `Codex` and as `Agent Skills`. The duplicate row exists so a Codex user sees the word "Codex", since one who saw only "Agent Skills" concluded Taskless did not support their harness. But Codex is not the only harness that reads `.agents/skills`, and a row per harness does not scale. OpenCode, Gemini CLI, and Crush all read it, and the picker names none of them.
4+
5+
## What Changes
6+
7+
- The picker offers one `.agents/` row, labelled with the detected harnesses that read `.agents/skills`, in catalog order: `OpenCode, Codex, and other .agents harnesses (.agents/)`. With none detected, it names all of them, so a Codex or Gemini CLI user still finds their harness on a fresh machine.
8+
- The duplicate `Codex` row is removed, along with `uniqueShimTargets()`, which existed only to collapse it.
9+
- Gemini CLI (`.gemini/`, `GEMINI.md`) and Crush (`.crush/`, `crush.json`, `.crushrc`, and variants) are detected and install into `.agents/`, each per its own docs.
10+
- OpenCode is named on the `.agents/` row when detected, since it reads `.agents/skills`, but does not pre-check it: it already gets `.opencode/`, and both would give it the skill twice.
11+
12+
## Delivery shape
13+
14+
**Stacked, merging forward**, on top of the `pinned-cli-permissions` stack (#509, #510). The change is independent of that stack, but it edits the `init` recipe the stack also edits, so it sits on top to avoid a conflict. Safe alone in production.
15+
16+
## Capabilities
17+
18+
### Modified Capabilities
19+
20+
- `cli-init`: the picker's `.agents/` row and its label; Gemini CLI and Crush detection.
21+
22+
## Impact
23+
24+
- `packages/cli/src/install/install.ts`: tool registry and shim catalog.
25+
- `packages/cli/src/wizard/steps/locations.ts`: the row label.
26+
- `packages/cli/src/agent/init.md`: the list of detected tools (topic v9).
27+
- Tests for the picker and detection.
28+
- No new harness gets a permission rule: Gemini CLI and Crush are not in the permission writer's closed list.
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
## MODIFIED Requirements
2+
3+
### Requirement: Wizard prompts the user to choose install locations
4+
5+
The wizard's location step SHALL be presented as a tool-selection step: "which tools do you want to enable Taskless for?". It SHALL offer one row per directory: `Claude Code` (`.claude/`), `Cursor` (`.cursor/`), `OpenCode` (`.opencode/`), and a row for `.agents/`. A user who arrived from a harness that reads `.agents/` SHALL NOT have to know that before recognising their harness in the list, so the `.agents/` row SHALL be labelled with harness names: the detected harnesses whose own documentation says they read `.agents/skills` (OpenCode, Codex, Gemini CLI, Crush), in catalog order, followed by `and other .agents harnesses`, for example `OpenCode, Codex, and other .agents harnesses (.agents/)`. When none of them is detected, the row SHALL name all of them, so a harness is still recognisable on a machine where nothing is detected.
6+
7+
Every list of directories derived from the catalog SHALL name each directory at most once, however many detected tools install into it. The pre-checked set SHALL be the union of (a) every directory recorded as a target in the install manifest (`install.targets`) that matches an offered row, and (b) every detected tool's install directory, deduplicated by directory. When the manifest records no targets AND no tools are detected, `.agents/` SHALL be pre-checked as the first-run default. The canonical `.taskless/` store SHALL NOT appear as a selectable entry and SHALL NOT be pre-checked — it is always written and is never a manifest tool-directory target.
8+
9+
Each offered entry SHALL carry an origin hint: `installed` when the entry's directory is recorded in the install manifest; otherwise `detected` when a detected tool installs into the entry's directory; otherwise `not detected`. A harness named on the `.agents/` row only because it reads `.agents/skills`, such as OpenCode, whose own directory is `.opencode/`, SHALL NOT make that row `detected` or pre-check it, since installing into both directories would give that harness the skill twice. The `installed` hint SHALL take precedence over `detected` when both apply.
10+
11+
Unchecking a pre-checked, manifest-recorded entry SHALL cause the resulting install plan to omit that target, so the existing manifest-diff removal path removes Taskless's reference stubs from that directory. The at-least-one-tool selection rule is unchanged: the wizard SHALL require at least one checked entry.
12+
13+
Each selected directory SHALL produce exactly one `reference` stub target; the resulting install plan always contains the single `taskless` skill and no command. The `.agents/` target SHALL be reported in the install summary as `Agent Skills`. The function that maps detected tools and manifest targets to multiselect choices SHALL be pure — it SHALL receive both the detected tools and the manifest target list as arguments and SHALL perform no filesystem access — so the mapping is unit-testable.
14+
15+
#### Scenario: Codex is named in the tool list
16+
17+
- **WHEN** the wizard renders the tool-selection multiselect with Codex detected, or with no `.agents` harness detected
18+
- **THEN** the `.agents/` row's label SHALL name `Codex`
19+
- **AND** exactly one entry SHALL be offered for `.agents/`
20+
21+
#### Scenario: Detected .agents harnesses are named in catalog order
22+
23+
- **WHEN** Codex and OpenCode are detected
24+
- **THEN** the `.agents/` row SHALL be labelled `OpenCode, Codex, and other .agents harnesses (.agents/)`
25+
26+
#### Scenario: OpenCode is named without pre-checking .agents
27+
28+
- **WHEN** OpenCode is the only detected tool
29+
- **THEN** the `.agents/` row's label SHALL name OpenCode
30+
- **AND** `.agents/` SHALL NOT be pre-checked and SHALL carry the `not detected` hint
31+
32+
#### Scenario: A directory offered by two rows is pre-checked once
33+
34+
- **WHEN** the wizard reaches the tool-selection step and Codex, Gemini CLI, and Crush are all detected
35+
- **THEN** `.agents/` SHALL appear exactly once in the pre-checked set
36+
37+
#### Scenario: A directory offered by two rows installs once
38+
39+
- **WHEN** the user's selection includes `.agents/`
40+
- **THEN** the install plan SHALL contain exactly one `.agents/` target
41+
- **AND** the `.agents/` skill stub SHALL be written once
42+
43+
#### Scenario: Detected tools are pre-checked
44+
45+
- **WHEN** the wizard reaches the tool-selection step and `.claude/` is detected
46+
- **THEN** `.claude/` SHALL be pre-checked in the multiselect
47+
- **AND** `.claude/` SHALL carry the `detected` hint when it is not recorded in the install manifest
48+
49+
#### Scenario: Manifest-recorded locations are pre-checked
50+
51+
- **WHEN** the wizard reaches the tool-selection step and the install manifest records `.agents/` as a target
52+
- **THEN** `.agents/` SHALL be pre-checked in the multiselect
53+
- **AND** `.agents/` SHALL carry the `installed` hint
54+
55+
#### Scenario: Installed hint takes precedence over detected
56+
57+
- **WHEN** the wizard reaches the tool-selection step and `.claude/` is both detected on the filesystem and recorded in the install manifest
58+
- **THEN** `.claude/` SHALL be pre-checked
59+
- **AND** `.claude/` SHALL carry the `installed` hint, not the `detected` hint
60+
61+
#### Scenario: Unchecking an installed location removes its stubs
62+
63+
- **WHEN** the install manifest records `.claude/` and `.agents/` as targets and the user unchecks `.claude/` while leaving `.agents/` checked
64+
- **THEN** the resulting install plan SHALL omit the `.claude/` target
65+
- **AND** the wizard summary SHALL list the `.claude/` reference stubs as removals
66+
67+
#### Scenario: Agents is the default when nothing is detected or installed
68+
69+
- **WHEN** the wizard reaches the tool-selection step, no tools are detected, and the install manifest records no tool-directory targets
70+
- **THEN** `.agents/` SHALL be pre-checked
71+
72+
#### Scenario: Canonical store is not a selectable entry
73+
74+
- **WHEN** the wizard renders the tool-selection multiselect
75+
- **THEN** `.taskless/` SHALL NOT appear as a selectable option
76+
- **AND** `.taskless/` SHALL NOT be pre-checked even though the manifest records it as a target
77+
78+
## ADDED Requirements
79+
80+
### Requirement: Gemini CLI and Crush detection signals
81+
82+
Gemini CLI and Crush SHALL be detected as harnesses that read `.agents/skills`, from their own documentation: Gemini CLI reads workspace skills from `.gemini/skills/` "or the `.agents/skills/` alias", and Crush lists `.agents/skills` among its project skill directories. Each SHALL install into `.agents/`.
83+
84+
Gemini CLI SHALL be detected when a `.gemini/` directory or a `GEMINI.md` file exists in the project root. Crush SHALL be detected when a `.crush/` directory, or a `.crushrc`, `crushrc`, `crush.json`, or `.crush.json` file, exists in the project root.
85+
86+
#### Scenario: Gemini CLI detected by its directory
87+
88+
- **WHEN** `.gemini/` exists in the project root
89+
- **THEN** Gemini CLI SHALL be detected
90+
- **AND** skills SHALL be installed to `.agents/skills/`
91+
92+
#### Scenario: Crush detected by its directory
93+
94+
- **WHEN** `.crush/` exists in the project root
95+
- **THEN** Crush SHALL be detected
96+
- **AND** skills SHALL be installed to `.agents/skills/`
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
## 1. One .agents row that names its harnesses
2+
3+
- [x] 1.1 Detect Gemini CLI and Crush; mark the harnesses that read `.agents/skills`
4+
- [x] 1.2 Collapse the catalog to one row per directory and drop `uniqueShimTargets()`
5+
- [x] 1.3 Label the `.agents/` row from detection, falling back to every known reader; OpenCode is named but does not pre-check it
6+
- [x] 1.4 Update the `init` recipe's tool list
7+
- [x] 1.5 Tests for the label, pre-check, and detection
8+
- [x] 1.6 Changeset; run `pnpm typecheck` and `pnpm lint`

‎openspec/specs/cli-init/spec.md‎

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -371,30 +371,41 @@ The wizard SHALL begin by rendering an ASCII rendition of the Taskless wordmark
371371

372372
### Requirement: Wizard prompts the user to choose install locations
373373

374-
The wizard's location step SHALL be presented as a tool-selection step: "which tools do you want to enable Taskless for?". It SHALL offer a fixed catalog of rows: `Claude Code` (`.claude/`), `Codex` (`.agents/`), `Cursor` (`.cursor/`), `OpenCode` (`.opencode/`), and `Agent Skills` (`.agents/`). A row names a tool the user scans for, so more than one row MAY offer the same directory: Codex reads `.agents/`, and a user who arrived from Codex SHALL NOT have to know that before recognising their harness in the list. The generic `Agent Skills` row SHALL remain, since it serves harnesses this catalog does not enumerate.
374+
The wizard's location step SHALL be presented as a tool-selection step: "which tools do you want to enable Taskless for?". It SHALL offer one row per directory: `Claude Code` (`.claude/`), `Cursor` (`.cursor/`), `OpenCode` (`.opencode/`), and a row for `.agents/`. A user who arrived from a harness that reads `.agents/` SHALL NOT have to know that before recognising their harness in the list, so the `.agents/` row SHALL be labelled with harness names: the detected harnesses whose own documentation says they read `.agents/skills` (OpenCode, Codex, Gemini CLI, Crush), in catalog order, followed by `and other .agents harnesses`, for example `OpenCode, Codex, and other .agents harnesses (.agents/)`. When none of them is detected, the row SHALL name all of them, so a harness is still recognisable on a machine where nothing is detected.
375375

376-
Every list of directories derived from the catalog SHALL name each directory at most once, however many rows offer it. The pre-checked set SHALL be the union of (a) every directory recorded as a target in the install manifest (`install.targets`) that matches an offered row, and (b) every detected tool's install directory, deduplicated by directory. When the manifest records no targets AND no tools are detected, `.agents/` SHALL be pre-checked as the first-run default. The canonical `.taskless/` store SHALL NOT appear as a selectable entry and SHALL NOT be pre-checked — it is always written and is never a manifest tool-directory target.
376+
Every list of directories derived from the catalog SHALL name each directory at most once, however many detected tools install into it. The pre-checked set SHALL be the union of (a) every directory recorded as a target in the install manifest (`install.targets`) that matches an offered row, and (b) every detected tool's install directory, deduplicated by directory. When the manifest records no targets AND no tools are detected, `.agents/` SHALL be pre-checked as the first-run default. The canonical `.taskless/` store SHALL NOT appear as a selectable entry and SHALL NOT be pre-checked — it is always written and is never a manifest tool-directory target.
377377

378-
Each offered entry SHALL carry an origin hint: `installed` when the entry's directory is recorded in the install manifest; otherwise `detected` when the entry's tool is detected on the filesystem; otherwise `not detected`. The generic `Agent Skills` row MAY instead carry a hint describing it as the generic agent-skills location; a row naming a specific harness SHALL NOT carry that hint. The `installed` hint SHALL take precedence over `detected` when both apply.
378+
Each offered entry SHALL carry an origin hint: `installed` when the entry's directory is recorded in the install manifest; otherwise `detected` when a detected tool installs into the entry's directory; otherwise `not detected`. A harness named on the `.agents/` row only because it reads `.agents/skills`, such as OpenCode, whose own directory is `.opencode/`, SHALL NOT make that row `detected` or pre-check it, since installing into both directories would give that harness the skill twice. The `installed` hint SHALL take precedence over `detected` when both apply.
379379

380380
Unchecking a pre-checked, manifest-recorded entry SHALL cause the resulting install plan to omit that target, so the existing manifest-diff removal path removes Taskless's reference stubs from that directory. The at-least-one-tool selection rule is unchanged: the wizard SHALL require at least one checked entry.
381381

382-
Each selected directory SHALL produce exactly one `reference` stub target, even when several offered rows name it; the resulting install plan always contains the single `taskless` skill and no command. A directory offered by more than one row SHALL be reported in the install summary under a single label. The function that maps detected tools and manifest targets to multiselect choices SHALL be pure — it SHALL receive both the detected tools and the manifest target list as arguments and SHALL perform no filesystem access — so the mapping is unit-testable.
382+
Each selected directory SHALL produce exactly one `reference` stub target; the resulting install plan always contains the single `taskless` skill and no command. The `.agents/` target SHALL be reported in the install summary as `Agent Skills`. The function that maps detected tools and manifest targets to multiselect choices SHALL be pure — it SHALL receive both the detected tools and the manifest target list as arguments and SHALL perform no filesystem access — so the mapping is unit-testable.
383383

384384
#### Scenario: Codex is named in the tool list
385385

386-
- **WHEN** the wizard renders the tool-selection multiselect
387-
- **THEN** a `Codex` entry SHALL be offered for `.agents/`
388-
- **AND** a separate generic `Agent Skills` entry SHALL also be offered for `.agents/`
386+
- **WHEN** the wizard renders the tool-selection multiselect with Codex detected, or with no `.agents` harness detected
387+
- **THEN** the `.agents/` row's label SHALL name `Codex`
388+
- **AND** exactly one entry SHALL be offered for `.agents/`
389+
390+
#### Scenario: Detected .agents harnesses are named in catalog order
391+
392+
- **WHEN** Codex and OpenCode are detected
393+
- **THEN** the `.agents/` row SHALL be labelled `OpenCode, Codex, and other .agents harnesses (.agents/)`
394+
395+
#### Scenario: OpenCode is named without pre-checking .agents
396+
397+
- **WHEN** OpenCode is the only detected tool
398+
- **THEN** the `.agents/` row's label SHALL name OpenCode
399+
- **AND** `.agents/` SHALL NOT be pre-checked and SHALL carry the `not detected` hint
389400

390401
#### Scenario: A directory offered by two rows is pre-checked once
391402

392-
- **WHEN** the wizard reaches the tool-selection step and Codex is detected
403+
- **WHEN** the wizard reaches the tool-selection step and Codex, Gemini CLI, and Crush are all detected
393404
- **THEN** `.agents/` SHALL appear exactly once in the pre-checked set
394405

395406
#### Scenario: A directory offered by two rows installs once
396407

397-
- **WHEN** the user's selection includes `.agents/`, whichever of its rows was checked
408+
- **WHEN** the user's selection includes `.agents/`
398409
- **THEN** the install plan SHALL contain exactly one `.agents/` target
399410
- **AND** the `.agents/` skill stub SHALL be written once
400411

@@ -1051,3 +1062,21 @@ The manifest SHALL record, under `install.permissions`, each file Taskless wrote
10511062

10521063
- **WHEN** `.claude/settings.json` also holds `Bash(npx @taskless/cli@0.12.0 *)`, which the manifest does not record
10531064
- **THEN** an upgrade SHALL leave that entry in place
1065+
1066+
### Requirement: Gemini CLI and Crush detection signals
1067+
1068+
Gemini CLI and Crush SHALL be detected as harnesses that read `.agents/skills`, from their own documentation: Gemini CLI reads workspace skills from `.gemini/skills/` "or the `.agents/skills/` alias", and Crush lists `.agents/skills` among its project skill directories. Each SHALL install into `.agents/`.
1069+
1070+
Gemini CLI SHALL be detected when a `.gemini/` directory or a `GEMINI.md` file exists in the project root. Crush SHALL be detected when a `.crush/` directory, or a `.crushrc`, `crushrc`, `crush.json`, or `.crush.json` file, exists in the project root.
1071+
1072+
#### Scenario: Gemini CLI detected by its directory
1073+
1074+
- **WHEN** `.gemini/` exists in the project root
1075+
- **THEN** Gemini CLI SHALL be detected
1076+
- **AND** skills SHALL be installed to `.agents/skills/`
1077+
1078+
#### Scenario: Crush detected by its directory
1079+
1080+
- **WHEN** `.crush/` exists in the project root
1081+
- **THEN** Crush SHALL be detected
1082+
- **AND** skills SHALL be installed to `.agents/skills/`

‎packages/cli/src/agent/init.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Topic: init (CLI v%(CLI_VERSION)s / topic v8)
1+
# Topic: init (CLI v%(CLI_VERSION)s / topic v9)
22

33
## Goal
44
Install or update the Taskless skill in this project, and migrate the
@@ -131,7 +131,8 @@ first step, not the whole job.
131131
## For a person at a terminal
132132

133133
`%(TASKLESS_CLI)s` with no subcommand launches an interactive wizard. It
134-
detects the installed tools (Claude Code, OpenCode, Cursor, Codex), asks
134+
detects the installed tools (Claude Code, OpenCode, Cursor, and the
135+
`.agents` harnesses Codex, Gemini CLI, and Crush), asks
135136
which to enable, offers a login (skippable), shows a diff against the
136137
previous install, then writes the canonical `taskless` skill once to
137138
`.taskless/` and a thin stub into each selected tool directory. Stale

0 commit comments

Comments
 (0)