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
4 changes: 4 additions & 0 deletions .changeset/environment-steps-run-init.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@
---

Fix the upgrade steps `agent ok` and `check` print. They told you to run the CLI with no arguments, which only installs from a terminal: anywhere else it printed the topic index and changed nothing. They now name `init`, which works in both.

Your agent now finishes the job after you upgrade. Moving the CLI stays yours to do, and once you have, the agent applies the rules instructions itself instead of handing them back. On a project launcher run, the upgrade step now names `npx` rather than a placeholder.

`agent ok` also offers the upgrade the way your harness runs it: with the `!` prefix in the Claude Code CLI, OpenCode, Codex, Gemini CLI, and Devin, and with `/shell` in Cursor. Another terminal is always offered, and it's the only offer when the harness isn't recognized.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-11-04
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## Context

`environmentStatusBlock` renders one instruction for every step: give them to the user. A stub-based `upgrade` command that an agent could run was drafted first and dropped. It would have let an allowed path run newly published code with nobody in the loop, and `npx <package>@<version> init` already moves the pin, repairs a broken one, and rewrites the launcher.

## Decisions

**The split follows what each step runs.** The cli and skill steps change what the project runs or what its harnesses read, so they stay the user's. `update` runs the recorded version and fetches nothing new. The rules recipe can rewrite rules, which is the kind of change an agent already makes and a person reviews in the diff.

**The rules step is the agent's on any invocation, not only a launcher run.** The agent just ran `agent ok` through that same invocation, so the harness that allowed it will normally allow `update`. A refusal falls back to the user.

**A rules step beside an upgrade waits.** The confirming `agent ok` reports what is owed after the move, which may be different. The agent never runs the step the first report listed.

**`npx` on a launcher run.** The launcher cannot reveal how the CLI was first installed, and `npx` is the documented upgrade spelling. Printing the agent-fill marker asked the agent to fill in a command it is not going to run.

## Risks / Trade-offs

- [A user declines the upgrade while the rules are owed on this CLI] → Declining is fine, and the passage says what follows. The upgrade stays listed, and the agent applies the rules step to the current CLI, because `check` and `verify` refuse until it is recorded.
- [The rules recipe can rewrite rules with no one watching] → That is what the agent already does when a person hands it the step, and the result is a reviewable diff.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Why

`agent ok` tells the agent not to run any of its steps. That is right for moving the CLI, which is the user's decision and runs newly published code. It is more than the rules step needs. Once the user has upgraded, the rules step runs the version the project already records, and walking that recipe is ordinary agent work. Today the agent hands that step back too, so an upgrade stops halfway unless the user also does the reconcile.

## What Changes

- **The user upgrades.** The cli and skill steps stay the user's. They name `init`, and say that in a terminal the same command without `init` opens the installer and its options.
- **Then the agent applies the rules step.** On its own, the rules step is the agent's: it runs the command and follows the recipe to the last step, and hands it to the user only if the command is refused. Beside a cli or skill step, it waits for the confirming `agent ok`, because a newer CLI can owe a different reconcile.
- **A launcher run names `npx` for the upgrade.** The cli step printed an agent-fill marker there, because the launcher is not a package runner.

## Capabilities

### New Capabilities

None.

### Modified Capabilities

- `cli-agent`: `agent ok` says who runs each step, and names `npx` for the upgrade on a launcher run.
- `skill-taskless`: the skill leaves upgrades to the user and applies the rules step.

## Impact

- `packages/cli/src/install/freshness.ts`, `src/prompts/recipes.ts`, `src/commands/agent.ts`, `src/util/package-manager.ts`.
- `skills/taskless/SKILL.md`.
- Replaces the "the agent never runs the steps" decision in `agent-ok-update-notice` for the rules step only.
- Delivery shape: **single PR**. It sits on #608, which changes the same spec requirement.
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
## MODIFIED Requirements

### Requirement: ok topic confirms the CLI can run

`taskless agent ok` SHALL serve the recipe at `packages/cli/src/agent/ok.md` through the same render path as every other topic, and exit 0. Serving it at all confirms the CLI can run. The rendered recipe SHALL carry the `# Topic:` header and the one-command-per-call paragraph. It SHALL NOT carry the fetch-time directive, because the preflight runs once per session rather than once per task, and SHALL NOT carry a survey invite.

The recipe's body SHALL be one of two passages, chosen from the environment state the CLI measured when the recipe was fetched:

- When nothing is out of date: `Your Taskless environment is up to date and you can proceed.`
- When one or more parts are out of date: `Your Taskless environment is out of date, the following steps are needed in order for commands to work reliably:`, followed by one numbered step per out-of-date part, in the order cli, skill, rules. Each step SHALL name what is out of date, say why it matters, and give the exact command that fixes it, spelled with the detected invocation. After the steps, the passage SHALL say who runs them. The cli and skill steps belong to the user: when either is present, the passage SHALL tell the agent to give them to the user to run themselves, rather than running them, and to run `<invocation> agent ok` again once the user says they are done. The rules step belongs to the agent: when it is the only step, the passage SHALL tell the agent to run its command and follow the recipe it prints to its last step, and to give the command to the user if it is refused. When it appears beside a cli or skill step, the passage SHALL tell the agent to leave it until the confirming `agent ok`, and to apply it the same way if that run still reports it. When the cli part is present, the passage SHALL say the user can decline the upgrade and what follows: the project stays on this CLI and the report keeps listing the upgrade, and a reported rules step is still owed on this CLI, so the agent applies it.

The three parts SHALL be decided as follows:

- **cli**: a newer version of the package this build is (`@taskless/cli` for a release build, `@taskless/cli-nightly` for a nightly) is published as `latest` than the running version, by semver precedence. The latest version SHALL be asked of the npm registry only, at most once per run, with a timeout of at most one second. The answer SHALL be used only when it is a strict semantic version (`MAJOR.MINOR.PATCH` with optional prerelease and build identifiers, and nothing else), because it is written into a command the user runs. A lookup that fails, times out, or returns a missing or invalid version SHALL leave this part out, and SHALL NOT change the output's form or the exit code. The lookup SHALL be skipped, and the part left out, in a CI environment, when `NO_UPDATE_NOTIFIER` is set to a non-empty value (the opt-out convention many CLIs honor), and on a build that is not a published package. The fixing command SHALL run `init` with that package at exactly the newer version, and the step SHALL say that in a terminal the same command without `init` opens the installer. A project launcher hides how the CLI was first installed, so when one started the CLI this command SHALL be spelled with `npx`.
- **skill**: the Taskless skill installed in the project is not the version this CLI carries, by the same comparison `taskless info` reports. The fixing command SHALL be `<invocation> init`, and the step SHALL say that in a terminal the same command without `init` opens the installer. When the cli part is also present, the skill step SHALL say that the cli step's command also refreshes the skill and SHALL give no separate command.
- **rules**: the project's rules are not reconciled to this CLI, by the same status `taskless info` and `taskless init` report. The fixing command SHALL be `<invocation> update`.

In a directory with no `.taskless/`, the skill and rules parts SHALL be left out. The command MAY read `.taskless/`, and SHALL NOT create or write it.

When the recipe is rendered by a caller that supplies no measured state, as the `@taskless/cli/prompts` export does, the body SHALL say that the environment was not checked, and SHALL claim neither outcome.

It SHALL emit the command's `cli_agent` intent event with `topic: "ok"`. The topic SHALL appear in the `taskless agent` index.

#### Scenario: ok prints one confirmation line

- **WHEN** `taskless agent ok` is run in a project where nothing is out of date
- **THEN** stdout SHALL begin with the `# Topic: ok` header line
- **AND** SHALL contain `Your Taskless environment is up to date and you can proceed.`
- **AND** the CLI SHALL exit with code 0

#### Scenario: ok carries no fetch-time directive

- **WHEN** `taskless agent ok` is run
- **THEN** its output SHALL NOT contain the fetch-time directive

#### Scenario: ok names the detected invocation

- **WHEN** `taskless agent ok` is run by a launcher the CLI detects, and reports an out-of-date part
- **THEN** each fixing command SHALL be spelled with that launcher

#### Scenario: ok does not guess an unknown launcher

- **WHEN** `taskless agent ok` is run, the launcher cannot be determined, and an out-of-date part is reported
- **THEN** each fixing command SHALL be spelled with the same agent-fill marker every recipe uses for an unknown invocation, and SHALL NOT name a guessed launcher

#### Scenario: ok runs outside a Taskless project

- **WHEN** `taskless agent ok` is run in a directory with no `.taskless/`
- **THEN** it SHALL serve the recipe and exit 0
- **AND** SHALL report neither the skill nor the rules part
- **AND** SHALL NOT create `.taskless/`

#### Scenario: ok reports a newer published CLI

- **WHEN** `taskless agent ok` is run and the published `latest` for this build's package is newer than the running version
- **THEN** the output SHALL contain the out-of-date passage
- **AND** a step SHALL name the running version and the newer one
- **AND** SHALL give a command that runs `init` with that package at exactly the newer version

#### Scenario: The out-of-date passage hands the steps to the user

- **WHEN** `taskless agent ok` reports the cli or skill part
- **THEN** the output SHALL tell the agent to have the user run those steps
- **AND** SHALL tell the agent to run `<invocation> agent ok` again once the user is done

#### Scenario: The agent applies a rules step on its own

- **WHEN** `taskless agent ok` reports only the rules part
- **THEN** the output SHALL tell the agent to run the step's command and follow its recipe to the last step
- **AND** SHALL NOT tell the agent to have the user run it, unless the command is refused

#### Scenario: A rules step waits for the upgrade

- **WHEN** `taskless agent ok` reports the rules part beside the cli part
- **THEN** the output SHALL tell the agent to leave the rules step until the confirming `agent ok`

#### Scenario: Declining an upgrade is explained

- **WHEN** `taskless agent ok` reports the cli part
- **THEN** the output SHALL say the user can decline, and that the project stays on this CLI and the report keeps listing the upgrade
- **AND** when the rules part is also reported, SHALL say the rules are still owed on this CLI and tell the agent to apply the rules step once the user declines

#### Scenario: A launcher run spells the upgrade with npx

- **WHEN** `./.taskless/bin/cli.mjs agent ok` is run and a newer CLI is published
- **THEN** the cli step's command SHALL be `npx <package>@<latest> init`

#### Scenario: A failed registry lookup is silent

- **WHEN** `taskless agent ok` is run, nothing local is out of date, and the registry lookup fails or exceeds its timeout
- **THEN** the output SHALL contain the up-to-date passage
- **AND** the CLI SHALL exit with code 0

#### Scenario: An invalid version is ignored

- **WHEN** `taskless agent ok` is run and the registry returns a `latest` that is not a strict semantic version
- **THEN** the cli part SHALL be left out
- **AND** the output SHALL NOT contain that string

#### Scenario: The registry is not asked in CI

- **WHEN** `taskless agent ok` is run in a CI environment, or with `NO_UPDATE_NOTIFIER` set
- **THEN** the CLI SHALL NOT contact the registry

#### Scenario: ok reports an out-of-date skill

- **WHEN** `taskless agent ok` is run in a project whose installed Taskless skill is not the version this CLI carries, and no newer CLI is reported
- **THEN** the output SHALL contain the out-of-date passage
- **AND** a step SHALL give `<invocation> init`

#### Scenario: A newer CLI subsumes the skill refresh

- **WHEN** `taskless agent ok` reports both the cli and skill parts
- **THEN** the skill step SHALL point to the cli step's command and SHALL give no command of its own

#### Scenario: ok reports rules owing a reconcile

- **WHEN** `taskless agent ok` is run in a project whose rules are not reconciled to this CLI
- **THEN** a step SHALL give `<invocation> update`

#### Scenario: ok does not write the project

- **WHEN** `taskless agent ok` is run in a project with a `.taskless/` directory
- **THEN** no file under `.taskless/` SHALL be created or modified

#### Scenario: The prompts export claims no outcome

- **WHEN** the `ok` recipe is rendered with no measured state
- **THEN** it SHALL say the environment was not checked
- **AND** SHALL contain neither the up-to-date nor the out-of-date passage

#### Scenario: ok is in the index

- **WHEN** `taskless agent` is run with no arguments
- **THEN** the index SHALL include a row for `ok`

#### Scenario: ok captures its topic

- **WHEN** `taskless agent ok` is run
- **THEN** PostHog SHALL receive a `cli_agent` event whose `topic` property is `ok`
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
## MODIFIED Requirements

### Requirement: Skill acts on the preflight's environment report

The skill body SHALL tell the agent that `%(TASKLESS_CLI)s agent ok` returns a recipe whose body reports whether the Taskless environment is up to date. When it reports the environment is up to date, the body SHALL instruct the agent to proceed with the user's request.

When it reports the environment is out of date, the body SHALL instruct the agent to give the user the steps that move the CLI or reinstall the skill, with their commands, once, for the user to run themselves, and SHALL NOT instruct the agent to run those steps. The body SHALL name the ways to run them: in Claude Code, typing the command with the `!` prefix, which runs it in the session's shell; or in another terminal. The reason is that moving the CLI is the user's decision. The body SHALL instruct the agent to carry on with the user's request, and, when the user says they ran the steps, to run `%(TASKLESS_CLI)s agent ok` again to confirm.

When a step says the rules owe a reconcile and no CLI or skill step is left, the body SHALL instruct the agent to run its command and follow the recipe it prints to its last step, and to give the command to the user if it is refused. The body SHALL say that when the user declines an upgrade, the agent tells them what that means, and applies a reported rules step to this CLI.

That confirming run is the only time the body SHALL instruct the agent to run the preflight again in a session once it has passed.

The `!` prefix offered here is distinct from the blocked-preflight guidance, which does not offer it. There, `!` would clear only the one preflight call and leave every later Taskless command blocked. Here, the steps are one-off commands, and running them once is the whole job.

#### Scenario: Skill body explains both outcomes

- **WHEN** the skill body is read from source
- **THEN** it SHALL describe the up-to-date and the out-of-date outcomes of `agent ok`

#### Scenario: Skill body hands the steps to the user

- **WHEN** the skill body is read from source
- **THEN** it SHALL instruct the agent, on an out-of-date report, to give the user the steps that move the CLI or reinstall the skill once, to run themselves
- **AND** SHALL name the `!` prefix in Claude Code and another terminal as the ways to run them
- **AND** SHALL NOT instruct the agent to run those steps itself
- **AND** SHALL instruct the agent to carry on with the user's request

#### Scenario: Skill body applies the rules step

- **WHEN** the skill body is read from source
- **THEN** it SHALL instruct the agent to run a rules step's command and follow its recipe once no CLI or skill step is left

#### Scenario: Skill body re-checks after the user updates

- **WHEN** the skill body is read from source
- **THEN** it SHALL instruct the agent, once the user says they ran the steps, to run `agent ok` again

#### Scenario: Skill body runs the preflight once otherwise

- **WHEN** the skill body is read from source
- **THEN** it SHALL NOT instruct the agent to run `agent ok` again in a session after it has passed, except to confirm the user's update
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## 1. Steps

- [x] 1.1 Say in the cli and skill steps that the command without `init` opens the installer in a terminal
- [x] 1.2 Render who runs each step in the `ok` passage
- [x] 1.3 Spell the cli step with `npx` on a launcher run
- [x] 1.4 Update the skill's preflight section

## 2. Ship

- [x] 2.1 Update the tests
- [x] 2.2 Grow the changeset
- [x] 2.3 Confirm every prior scenario survives the archive
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-11-04
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## Context

No code in the CLI asks which harness started it. A wrong answer here costs little: the output is a suggestion, and another terminal is always offered.

## Decisions

**Vendor variables from a fixed table, for wording only.** Variables are not a shared standard: `AI_AGENT` is an open proposal, and its values differ by product. So each row names a variable that product sets and a prefix it documents, and nothing from the environment reaches the output. Any process can set these, so they never decide what is allowed.

**Only harnesses Taskless installs for, and only documented syntax.** Crush installs but documents no such prefix, so it gets a terminal. Copilot CLI, Aider, and Amp have prefixes and are not in the installer.

**`!` only on Claude Code's CLI entrypoint.** The VS Code extension sets `CLAUDECODE` and has no `!` shortcut, so `CLAUDE_CODE_ENTRYPOINT` narrows it.

**Cursor states its limit.** `/shell` stops at 30 seconds and takes no prompts, and a first `npx` of a version can take longer, so the passage names another terminal for that case.

## Risks / Trade-offs

- [`CURSOR_AGENT` was reported unset by Cursor's CLI in 2025, and `CODEX_THREAD_ID` is undocumented] → A miss falls back to another terminal, which works.
- [Harness variables are inherited, so a nested agent can read as its parent] → The prefix may name the outer harness. Another terminal is still offered.
- [Prefixes change] → Each row cites its source, and a stale row costs one wrong suggestion.
Loading
Loading