Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .changeset/pinned-cli-permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ Released builds now pin their own version. The installed skill and the `agent` r
`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.

`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.

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/`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
## Why

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.

## What Changes

- 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.
- The duplicate `Codex` row is removed, along with `uniqueShimTargets()`, which existed only to collapse it.
- Gemini CLI (`.gemini/`, `GEMINI.md`) and Crush (`.crush/`, `crush.json`, `.crushrc`, and variants) are detected and install into `.agents/`, each per its own docs.
- 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.

## Delivery shape

**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.

## Capabilities

### Modified Capabilities

- `cli-init`: the picker's `.agents/` row and its label; Gemini CLI and Crush detection.

## Impact

- `packages/cli/src/install/install.ts`: tool registry and shim catalog.
- `packages/cli/src/wizard/steps/locations.ts`: the row label.
- `packages/cli/src/agent/init.md`: the list of detected tools (topic v9).
- Tests for the picker and detection.
- No new harness gets a permission rule: Gemini CLI and Crush are not in the permission writer's closed list.
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
## MODIFIED Requirements

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

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.

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.

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.

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.

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.

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

- **WHEN** the wizard renders the tool-selection multiselect with Codex detected, or with no `.agents` harness detected
- **THEN** the `.agents/` row's label SHALL name `Codex`
- **AND** exactly one entry SHALL be offered for `.agents/`

#### Scenario: Detected .agents harnesses are named in catalog order

- **WHEN** Codex and OpenCode are detected
- **THEN** the `.agents/` row SHALL be labelled `OpenCode, Codex, and other .agents harnesses (.agents/)`

#### Scenario: OpenCode is named without pre-checking .agents

- **WHEN** OpenCode is the only detected tool
- **THEN** the `.agents/` row's label SHALL name OpenCode
- **AND** `.agents/` SHALL NOT be pre-checked and SHALL carry the `not detected` hint

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

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

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

- **WHEN** the user's selection includes `.agents/`
- **THEN** the install plan SHALL contain exactly one `.agents/` target
- **AND** the `.agents/` skill stub SHALL be written once

#### Scenario: Detected tools are pre-checked

- **WHEN** the wizard reaches the tool-selection step and `.claude/` is detected
- **THEN** `.claude/` SHALL be pre-checked in the multiselect
- **AND** `.claude/` SHALL carry the `detected` hint when it is not recorded in the install manifest

#### Scenario: Manifest-recorded locations are pre-checked

- **WHEN** the wizard reaches the tool-selection step and the install manifest records `.agents/` as a target
- **THEN** `.agents/` SHALL be pre-checked in the multiselect
- **AND** `.agents/` SHALL carry the `installed` hint

#### Scenario: Installed hint takes precedence over detected

- **WHEN** the wizard reaches the tool-selection step and `.claude/` is both detected on the filesystem and recorded in the install manifest
- **THEN** `.claude/` SHALL be pre-checked
- **AND** `.claude/` SHALL carry the `installed` hint, not the `detected` hint

#### Scenario: Unchecking an installed location removes its stubs

- **WHEN** the install manifest records `.claude/` and `.agents/` as targets and the user unchecks `.claude/` while leaving `.agents/` checked
- **THEN** the resulting install plan SHALL omit the `.claude/` target
- **AND** the wizard summary SHALL list the `.claude/` reference stubs as removals

#### Scenario: Agents is the default when nothing is detected or installed

- **WHEN** the wizard reaches the tool-selection step, no tools are detected, and the install manifest records no tool-directory targets
- **THEN** `.agents/` SHALL be pre-checked

#### Scenario: Canonical store is not a selectable entry

- **WHEN** the wizard renders the tool-selection multiselect
- **THEN** `.taskless/` SHALL NOT appear as a selectable option
- **AND** `.taskless/` SHALL NOT be pre-checked even though the manifest records it as a target

## ADDED Requirements

### Requirement: Gemini CLI and Crush detection signals

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/`.

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.

#### Scenario: Gemini CLI detected by its directory

- **WHEN** `.gemini/` exists in the project root
- **THEN** Gemini CLI SHALL be detected
- **AND** skills SHALL be installed to `.agents/skills/`

#### Scenario: Crush detected by its directory

- **WHEN** `.crush/` exists in the project root
- **THEN** Crush SHALL be detected
- **AND** skills SHALL be installed to `.agents/skills/`
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## 1. One .agents row that names its harnesses

- [x] 1.1 Detect Gemini CLI and Crush; mark the harnesses that read `.agents/skills`
- [x] 1.2 Collapse the catalog to one row per directory and drop `uniqueShimTargets()`
- [x] 1.3 Label the `.agents/` row from detection, falling back to every known reader; OpenCode is named but does not pre-check it
- [x] 1.4 Update the `init` recipe's tool list
- [x] 1.5 Tests for the label, pre-check, and detection
- [x] 1.6 Changeset; run `pnpm typecheck` and `pnpm lint`
47 changes: 38 additions & 9 deletions openspec/specs/cli-init/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,30 +371,41 @@ The wizard SHALL begin by rendering an ASCII rendition of the Taskless wordmark

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

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.
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.

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.
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.

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.
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.

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.

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.
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.

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

- **WHEN** the wizard renders the tool-selection multiselect
- **THEN** a `Codex` entry SHALL be offered for `.agents/`
- **AND** a separate generic `Agent Skills` entry SHALL also be offered for `.agents/`
- **WHEN** the wizard renders the tool-selection multiselect with Codex detected, or with no `.agents` harness detected
- **THEN** the `.agents/` row's label SHALL name `Codex`
- **AND** exactly one entry SHALL be offered for `.agents/`

#### Scenario: Detected .agents harnesses are named in catalog order

- **WHEN** Codex and OpenCode are detected
- **THEN** the `.agents/` row SHALL be labelled `OpenCode, Codex, and other .agents harnesses (.agents/)`

#### Scenario: OpenCode is named without pre-checking .agents

- **WHEN** OpenCode is the only detected tool
- **THEN** the `.agents/` row's label SHALL name OpenCode
- **AND** `.agents/` SHALL NOT be pre-checked and SHALL carry the `not detected` hint

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

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

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

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

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

- **WHEN** `.claude/settings.json` also holds `Bash(npx @taskless/cli@0.12.0 *)`, which the manifest does not record
- **THEN** an upgrade SHALL leave that entry in place

### Requirement: Gemini CLI and Crush detection signals

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/`.

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.

#### Scenario: Gemini CLI detected by its directory

- **WHEN** `.gemini/` exists in the project root
- **THEN** Gemini CLI SHALL be detected
- **AND** skills SHALL be installed to `.agents/skills/`

#### Scenario: Crush detected by its directory

- **WHEN** `.crush/` exists in the project root
- **THEN** Crush SHALL be detected
- **AND** skills SHALL be installed to `.agents/skills/`
5 changes: 3 additions & 2 deletions packages/cli/src/agent/init.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Topic: init (CLI v%(CLI_VERSION)s / topic v8)
# Topic: init (CLI v%(CLI_VERSION)s / topic v9)

## Goal
Install or update the Taskless skill in this project, and migrate the
Expand Down Expand Up @@ -133,7 +133,8 @@ first step, not the whole job.
## For a person at a terminal

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