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
29 changes: 29 additions & 0 deletions .changeset/codex-install-picker-row.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
"@taskless/cli": patch
---

Name Codex in the install picker, so Codex users can see that it supports them.

Codex has always been detected and installed into `.agents/`. The tool-selection
step just never said so: it read `Claude Code / Cursor / OpenCode / Agent
Skills`, and the entry that serves Codex is the one whose label only makes sense
if you already know `AGENTS.md` is the file Codex reads. A GPT-centric founder
looked at that list and concluded we did not support GPT. He was wrong, and the
list is why he thought it. Somebody who believes their harness is unsupported
does not file a bug, they leave.

The picker now offers a `Codex` row alongside the generic `Agent Skills` row,
both pointing at `.agents/`. Two rows for one directory is deliberate: people
scan a list for the name of the tool they use, and `Agent Skills` still has to
be there for anyone on a harness the catalog does not enumerate. Neither label
is redundant, so neither one goes.

That makes the catalog a list of rows rather than a list of directories, which
was an assumption the code held in three places. A single `.agents/` selection
used to match one row; it now matches two, and would have been pre-checked
twice, planned twice, written twice, and reported twice in the install summary.
The pre-checked set, `detectSelectedDirectories`, and the install plan all
collapse the catalog on `dir` first. The dedupe is on the directory rather than
on the Codex row specifically, so the next pair of rows that share a
destination inherits it instead of reintroducing the bug. Ticking either row
selects `.agents/` once, and ticking both is the same install as ticking one.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
## Why

Codex is detected, routed to `.agents/`, and fully supported. The word
"Codex" never appears in the list the user actually reads.

The install wizard keeps two lists. `TOOLS` drives detection and knows about
Codex. `SHIM_TARGETS` drives the "which tools do you want to enable Taskless
for?" multiselect and offers `Claude Code / Cursor / OpenCode / Agent Skills`.
A Codex user reads that list and concludes we do not support their harness,
because the support arrives under a label that only makes sense once you
already know `AGENTS.md` is the thing Codex reads. Someone who believes their
harness is unsupported does not file a bug, they leave.

## What Changes

- **The picker gains a `Codex` row pointing at `.agents/`.** Two rows now name
the same directory. That is the point: people scan the list for the name of
the tool they use. `Agent Skills` stays, because it is the entry that serves
anyone on a harness the catalog does not enumerate.
- **The catalog becomes a list of rows, not a list of directories.** Every
consumer that turns rows into directories or into install targets now goes
through a single deduplicating helper, so a shared directory is pre-checked
once, planned once, written once, and reported once. The dedupe is on `dir`,
not on the Codex row, so a future pair of rows sharing a destination
inherits the invariant.
- **The generic hint follows the generic row.** `generic agent skills` belongs
to the `Agent Skills` row; the `Codex` row hints `detected` or
`not detected` like any other named harness.

**Delivery is a single PR.** One catalog row, one helper, three call sites,
tests, and a spec delta. No unit of this is meaningful on its own.

## Capabilities

### Modified Capabilities

- `cli-init`: the tool-selection step names Codex, and a directory offered by
more than one row installs exactly once.

## Impact

- **Modified**: `packages/cli/src/install/install.ts` (the `Codex` row,
`uniqueShimTargets`, `detectSelectedDirectories`, `buildInstallPlan`),
`packages/cli/src/wizard/steps/locations.ts` (pre-checked set and hints),
`packages/cli/test/install.test.ts`,
`packages/cli/test/wizard-steps.test.ts`.
- **Unchanged**: detection, the canonical store, the stub format, and the
install manifest, which has always been keyed by directory.

**Tracking:** taskless/cli#204
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
## 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 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.

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.

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.

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, for `.claude/` and `.cursor/`, the `tskl` 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.

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

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

- **WHEN** the wizard reaches the tool-selection step and Codex is 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
- **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
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Delivery shape: **single PR**. One catalog row, one deduplicating helper, its call sites, tests, and a spec delta. Landing the row without the dedupe would install `.agents/` twice, so the units are only correct together.

## 1. Catalog

- [x] 1.1 Add the `Codex` row on `.agents/`, ordered so named harnesses come before the generic `Agent Skills` fallback
- [x] 1.2 Add `uniqueShimTargets`, collapsing the catalog to one entry per directory in catalog order
- [x] 1.3 Say in the code why two rows share a directory, so it is not deleted as a duplicate later
- [x] 1.4 Update the `ShimTarget` doc comment, which read as promising one row per directory

## 2. Call sites

- [x] 2.1 `detectSelectedDirectories` maps the deduplicated catalog
- [x] 2.2 `buildInstallPlan` iterates the deduplicated catalog
- [x] 2.3 The wizard's pre-checked set is deduplicated; its options stay one per row
- [x] 2.4 The `generic agent skills` hint follows the generic row rather than the directory

## 3. Tests

- [x] 3.1 The picker lists Codex and Agent Skills as separate rows
- [x] 3.2 `detectSelectedDirectories` returns `.agents` once when Codex is detected
- [x] 3.3 `locationChoices` pre-checks `.agents` once when Codex is detected
- [x] 3.4 A selection naming `.agents` produces exactly one plan target, labelled `Agent Skills`
- [x] 3.5 An install of that plan writes each `.agents` skill stub once

## 4. Verification

- [x] 4.1 Confirm the tests fail with the dedupe removed
- [x] 4.2 Exercise the built CLI against a scratch directory outside the repo
- [x] 4.3 `pnpm build`, `pnpm typecheck`, `pnpm lint`, `pnpm test`, `pnpm cli check`
- [x] 4.4 `pnpm openspec validate --all --strict`
- [x] 4.5 Changeset
25 changes: 22 additions & 3 deletions openspec/specs/cli-init/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,13 +380,32 @@ 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 multiselect of `.claude/`, `.cursor/`, `.opencode/`, and `.agents/`. The pre-checked set SHALL be the union of (a) every directory recorded as a target in the install manifest (`install.targets`) that matches one of the four offered entries, and (b) every detected tool's install 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.
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.

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 `.agents/` first-run default MAY instead carry a hint describing it as the generic agent-skills location). The `installed` hint SHALL take precedence over `detected` when both apply.
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.

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.

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 checked entry SHALL produce one `reference` stub target; the resulting install plan always contains the single `taskless` skill (and, for `.claude/` and `.cursor/`, the `tskl` command). 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, even when several offered rows name it; the resulting install plan always contains the single `taskless` skill (and, for `.claude/` and `.cursor/`, the `tskl` 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.

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

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

- **WHEN** the wizard reaches the tool-selection step and Codex is 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
- **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

Expand Down
Loading
Loading