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

Rewrite the CLI README around what you actually do with Taskless: installing it,
driving it from your coding agent with the `taskless` skill and `/tskl` command,
running `taskless check` in CI, and where to find the docs. Telemetry — and the
two environment variables that turn it off — is now stated plainly instead of
being left to the source.
254 changes: 61 additions & 193 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
@@ -1,235 +1,103 @@
# @taskless/cli

> A Work in Progress
CLI companion for [Taskless](https://taskless.io). Designed to work with agent skills to add constraints that improve coding agent output.

CLI companion for [Taskless](https://taskless.io). Designed to be invoked by skills via `npx` or `pnpm dlx`. Useful for agents, and works for humans too.

## Usage
## Install

```bash
# npm
npx @taskless/cli@latest info
npx @taskless/cli

# pnpm
pnpm dlx @taskless/cli@latest info
```

## Commands

### `taskless info`

Outputs CLI version, tool status, and login info as JSON to stdout:

```json
{
"version": "0.0.3",
"tools": [],
"loggedIn": true,
"auth": { "user": "jake", "email": "jake@example.com", "orgs": ["my-org"] }
}
```

### `taskless init`

Launches an interactive wizard that detects supported tool directories in the
current project (`.claude/`, `.opencode/`, `.cursor/`, `.agents/`), asks which
tools to enable Taskless for, and walks through the auth tradeoff before
writing anything. Running `taskless` with no subcommand in a TTY also launches
this wizard. Without a TTY, bare `taskless` prints a short context preamble
followed by the topic index from `taskless agent`.

In v0.7+, there is exactly one skill (`taskless`) and one command (`tskl`) —
no opt-in selection needed.

The skill and command content is written **once** to a canonical store in
`.taskless/skills/` and `.taskless/commands/`. Each enabled tool directory
receives only a thin reference stub — an ordinary file with a delegating body,
never a symlink — so there is a single source of truth and no drift between
copies. Stale layouts from earlier versions (full per-tool copies, symlinks)
are converged into stubs automatically on the next `init`/`update`.

For CI and scripted installs, pass `--no-interactive` to skip all prompts:

```bash
taskless init # interactive wizard (default in a TTY)
taskless init --no-interactive # scripted install, no prompts
pnpm dlx @taskless/cli
```

The wizard records what it installed in `.taskless/taskless.json` so later
runs can compute a diff and surgically remove files that are no longer
selected. Upgrading from v0.6 automatically removes the obsolete per-task
skills and commands during this diff. Cancelling the wizard at any step
(Ctrl-C) aborts cleanly with no filesystem changes.

### `taskless onboard`

Post-install discovery flow that helps a fresh user go from zero rules to a
useful starter set. Run it after `taskless init`. The CLI prints an
agent-facing recipe that walks the host AI tool through scanning the
codebase, agent-memory files (CLAUDE.md / AGENTS.md / .cursorrules),
recent PR review comments (when `gh` is available), and issue tracker
tickets (when a relevant MCP is wired in) for high-signal rule
candidates, then surfaces them as a bullet list the user can choose to
materialize via `taskless rule create`.
Run with no arguments in a terminal to launch the installer, which detects the
agent tools in your project (Claude Code, Cursor, OpenCode) and installs into
each of them. For scripted installs, skip the prompts:

```bash
taskless onboard # print the recipe (refused if already complete)
taskless onboard --force # re-run even when previously marked complete
taskless onboard --mark-complete # record completion in .taskless/taskless.json
# (invoked by the agent after explicit user
# confirmation; never automatically)
npx @taskless/cli init --no-interactive
```

Onboarding state lives in `.taskless/taskless.json` as
`install.onboarded` — a 3-state optional field (absent / `false` / `true`).
Only the agent writes it, and only with the user's explicit confirmation.
`taskless init` does not set it. Pass `--force` to re-run regardless of the
current value.

After a successful `taskless init`, the CLI prints a one-line trailer
pointing the user at this command. The trailer wording adapts to the
install plan: when the install included slash commands (Claude Code or
Cursor), it mentions `/tskl onboard` along with the Taskless skill and the
bare CLI; when the install only wrote skills (OpenCode, Codex, the
`.agents/` fallback), it mentions the skill and the bare CLI only.
New to Taskless? Run `npx @taskless/cli onboard` after installing — it walks your
agent through your codebase and suggests a starter set of rules.

### `taskless check`
## How to Use via Agents

Run ast-grep rules from `.taskless/sg/rules/` against the codebase. Exits with code 1 if any error-severity matches are found.
Installing adds one skill (`taskless`) and one slash command (`/tskl`). The skill
body is a small router: your agent fetches the canonical recipe for whatever you
asked for, then follows it.

```bash
taskless check # human-readable output, scans whole project
taskless check --json # JSON output
```

Accepts optional positional path arguments to scan only specific files or
directories — useful for CI workflows that only want to check changed files.
Paths that don't exist on disk (e.g. files deleted in a diff) are silently
filtered, so raw git-diff output can be piped in directly:

```bash
taskless check src/foo.ts src/bar.ts
taskless check $(git diff --name-only main...HEAD) # PR-only scan
taskless check $(git diff --cached --name-only) # pre-commit scan
/tskl create a rule that bans console.log
/tskl add taskless to CI
```

If every supplied path is missing, the command exits 0 with empty results.
Plain language works too — "write a taskless rule for X", "run taskless check",
"taskless login" all engage the skill. You rarely need to run the CLI yourself.

### `taskless auth login` / `taskless auth logout`
To see what the agent sees, run `npx @taskless/cli agent` for the topic index, or
`npx @taskless/cli agent <topic>` for a full recipe.

Authenticate with taskless.io using the device flow. Tokens are stored in `~/.config/taskless/auth.json`.
## Taskless Check (CI and Constraints)

### `taskless rule create`

Generate ast-grep rules via the taskless.io API. Reads a JSON request from stdin, submits it, polls for results, and writes rule and test files to `.taskless/sg/rules/` and `.taskless/sg/rule-tests/`.
`taskless check` runs your rules against the codebase. It exits `0` when nothing
error-severity matched and `1` when something did, so it drops straight into a
pipeline:

```bash
echo '{"prompt": "detect console.log usage"}' | taskless rule create
echo '{"prompt": "find innerHTML assignments", "language": "typescript"}' | taskless rule create --json
npx @taskless/cli check # scan everything
npx @taskless/cli check $(git diff --name-only main...HEAD) # PR-only scan
npx @taskless/cli check --json # machine-readable
```

Requires authentication and a `.taskless/taskless.json` with `orgId` and `repositoryUrl`.
Paths that no longer exist are dropped silently, so raw `git diff` output can be
piped in without pre-filtering. Static rules need no login and make no network
calls, so CI needs no secrets. Runtime rules — which execute code — only run once
the server has verified their signature; otherwise they are reported as skipped
and never change the exit code.

### `taskless rule delete <id>`
Ask your agent to `/tskl add taskless to CI` and it will wire this into the CI
system you already use rather than replacing it.

Remove a rule file and its associated test files from disk. No authentication required.
## Why Teams Choose Taskless

```bash
taskless rule delete no-console-log
```
- **Constraints, not suggestions.** Rules are real files in your repo, enforced
by ast-grep, Vale, and runtime checks — the same result every run, for every
agent and every human.
- **The same rules in the editor and in CI.** One command, one exit code.
- **Works with the agent you already have.** One skill installs into Claude Code,
Cursor, and OpenCode — plus the `/tskl` command wherever the tool supports slash
commands — with a plain `.agents/` fallback when none is detected.
- **Nothing to run locally.** No daemon, no install step in CI, no auth for the
checks that matter most.

### `taskless --help`
## Docs

Lists available subcommands.
- [docs.taskless.io](https://docs.taskless.io) — guides and reference
- [taskless.io](https://taskless.io) — the product
- [github.com/taskless/cli](https://github.com/taskless/cli) — source and issues

### `taskless agent [topic]`
<details>
<summary><strong>Other</strong></summary>

Returns agent-facing recipes. With no args, prints the topic index. With a
topic (e.g. `taskless agent route`), prints the full step-by-step recipe
for that operation, including an embedded JSON Schema for any `--from` input
and a table of stable error codes. Append `--anonymous` to fetch the
local-only variant where one exists (currently `rule create`/`rule improve`).
### Telemetry

Recipes are how the consolidated `taskless` skill stays small while still
covering every operation — the skill body is a router that fetches the
relevant recipe on demand.

### `--anonymous` flag

Recognized on every command. Behavior matrix:

- `rule create` / `rule improve` — exits with a pointer to
`taskless agent <topic> --anonymous`. The local-only flow runs in the agent
per the recipe variant.
- `info` — skips the API/auth probe; reports local state only.
- `auth login` — rejected (auth commands cannot be anonymous).
- All others — accepted as no-op.

## For skill authors

Skills should detect the package manager by checking for lock files and invoke the CLI accordingly:

1. If `pnpm-lock.yaml` exists, use `pnpm dlx @taskless/cli@latest <command>`
2. Otherwise, use `npx @taskless/cli@latest <command>`

All commands output structured JSON to stdout by default. Parse with `JSON.parse()` and handle non-zero exit codes as errors.

## Developing

### Testing
The CLI reports anonymous usage — which command ran, whether it succeeded, how
long it took, and counts of findings. It never sends rule content, prompts, or
matched source. Disable it by setting either environment variable:

```bash
pnpm --filter @taskless/cli test # run the suite once
pnpm --filter @taskless/cli exec vitest # watch mode
export TASKLESS_TELEMETRY_DISABLED=1
# or the cross-tool convention
export DO_NOT_TRACK=1
```

The suite runs entirely locally under vitest — no network, no auth, no agent.
Integration tests that exercise the built binary (for example `detect`) run
against `dist/`, so run `pnpm --filter @taskless/cli build` first (or after any
source change) before invoking them directly.

**Two kinds of test, one of which is not fully automatable.** Most tests are
deterministic unit/integration checks. The route-honesty dataset
(`test/fixtures/route-eval.json`) is different: the actual routing decision is
made by an _agent_ following `help/route.txt`, so it cannot be asserted by a
code classifier. The automated test (`test/route-eval.test.ts`) therefore only
**guards the dataset** — that it stays structurally valid and balanced across
every route and both failure directions (over-claim / over-escalate). Running
the dataset _as an evaluation_ — feeding each case to an agent and scoring its
chosen destination — is a separate, manual calibration step with more setup; it
is not part of `pnpm test`. Keep the two distinct: the suite proves the fixtures
are well-formed; an agent run proves the recipe routes honestly.

### API base URL

The CLI resolves the API base URL in this order:
With either set, no client is created and no network request is made.

1. `TASKLESS_API_URL` env var
2. `~/.config/taskless/config.json` → `apiUrl` field
3. Default: `https://app.taskless.io/cli`
</details>

For local development against the taskless.io app:

```bash
TASKLESS_API_URL=http://localhost:5173/cli taskless info
```

### API schema introspection

All `/cli/api/*` endpoints support the `x-explain: 1` header. When present, the endpoint returns its JSON schema instead of executing — no authentication required.

```bash
# List available endpoints
curl -s -H "x-explain: 1" http://localhost:5173/cli/api

# Get the schema for rule generation
curl -s -H "x-explain: 1" -X POST http://localhost:5173/cli/api/rule

# Get the schema for rule status polling
curl -s -H "x-explain: 1" http://localhost:5173/cli/api/rule/any-id

# Get the schema for whoami
curl -s -H "x-explain: 1" http://localhost:5173/cli/api/whoami
```
---

This is useful for verifying that CLI types align with the production API contract.
MIT licensed.
Loading