npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@coldtea/tasks

v0.1.2

Published

The coldtea-tasks command line: read and file Coldtea tasks from a terminal or CI.

Downloads

529

Readme

@coldtea/tasks — the coldtea-tasks CLI

Read and file Coldtea tasks from a terminal or CI: list what is open, look a task up by the identifier a person would quote, and file one from a script. Every command talks to the public /v1 API and nothing else.

Install

The published package has ZERO runtime dependencies: @coldtea/cli-core, the half every Coldtea command line shares, is bundled into dist/main.js at build time. In the monorepo, npm install builds it via the package's prepare script; npm run build -w @coldtea/tasks rebuilds it by hand. Needs Node >= 20.6.

The package installs two names for the same binary: coldtea-tasks, and ctask for short — fewer tokens for the agents that call it most. The 0.1.0 two-word spelling (ctask tasks list) keeps working; the noun-less form is the one the help teaches.

Inside this monorepo:

node packages/tasks-cli/bin/coldtea-tasks.mjs --help

The API reference

The CLI talks to /v1 and nothing else, so the API reference is also the CLI's reference for what any command can do:

https://www.coldtea.ai/openapi/coldtea-v1.json

OpenAPI 3.1, generated from the routes themselves. It covers QA and Tasks together — one API, one key, scopes saying which product an endpoint belongs to.

Auth

Create an API key in the Coldtea dashboard with a Tasks scope, then:

export COLDTEA_API_KEY=coldtea_sk_…
coldtea-tasks whoami

The key identifies your TeaHouse; there is no TeaHouse flag, and /v1 rejects one with a 400 rather than ignoring it. --api-key overrides the environment. COLDTEA_BASE_URL points the CLI at another API origin — https only (every request carries the key), with loopback http allowed for dev and COLDTEA_ALLOW_INSECURE_HTTP=1 as the explicit opt-out for an http-only private host.

Two scopes exist. tasks:read lists and reads; tasks:write also creates. tasks:* is a real scope rather than shorthand, and a key holding it gains any tasks scope added later — where a key holding the enumerated two does not. A key with only QA scopes authenticates fine and is refused by every command here, which whoami says out loud rather than leaving you to infer from a 403.

Getting started

A title is enough to file a task: the server defaults the team to your TeaHouse's only team, and the column to that team's Todo. The reads below are for when you want to CHOOSE — several teams, a different column, an assignee:

ctask whoami                     # which TeaHouse, and what the key may do
ctask create "Title"             # files it in your only team's Todo column
ctask teams list                 # team ids, for when you have several
ctask states list                # board columns (--team only if several teams), for --state
ctask labels list                # label ids for --label
ctask members list               # user ids for --assignee
export COLDTEA_TEAM_ID=team_…            # stop repeating --team

Every one of those is a read. Teams, columns, labels and members are created in the dashboard, because each of them changes what everyone on the team sees; tasks:write means tasks.

members list carries no email addresses. Assigning needs the id and recognising a colleague needs the name, and a CLI's output ends up in logs that are kept and sometimes public.

Tasks

ctask list
ctask list --state wfs_… --priority urgent --limit 50
ctask list --label lbl_… --label lbl_…   # BOTH labels (repeats combine as AND)
ctask list --search "flaky login"        # title match, case-insensitive
ctask list --updated-since 2h            # 15m, 2h, 7d, or an epoch-ms instant
ctask list --state-type started          # a column's MEANING, across every team
ctask list --parent ORA-12               # one task's subtasks
ctask get ORA-12
ctask get ORA-12 --description
ctask create "Checkout drops the saved card"
ctask create "…" --team team_… --state wfs_…   # choose instead
ctask update ORA-12 --priority urgent --assignee usr_…
ctask update ORA-12 --assignee none        # clear it
ctask update ORA-12 --state wfs_…          # move between columns
ctask delete ORA-12

A task is named either by the identifier a person would quote — ORA-12, the team's key and the task's number — or by its canonical id. Both work everywhere a task id is taken.

Filters combine, and filtered pages can run short. Every filter narrows; a page may hold fewer than --limit rows and still have a next page, so follow meta.nextCursor, never row counts. --updated-since refuses bare 10-digit numbers on purpose: date +%s prints seconds, the API takes milliseconds, and a guess between them would silently match every task ever.

Priority is a word, not a number. none, urgent, high, medium, low. The underlying scale runs 1 for urgent to 4 for low, which is the reverse of what most people guess, so the number is never the input.

--state is optional, and the default is the server's. Omitted, the task lands in the team's Todo column — its leftmost unstarted state, the same column the product itself files into. To choose, states list shows the ids. Read a column's type to decide what it MEANS — a team may hold several columns of one type, so completed is the test for done, not a name. A blank --state or --team (usually an unset shell variable) is refused rather than read as "the default".

Descriptions are Markdown, and tasks list does not print them:

ctask create "Flaky checkout" --description-file ./report.md
cat report.md | ctask create "…" --description-file -
ctask get ORA-12 --description

A description is where pasted output goes — an agent filing a task through MCP can put a log, a stack trace or a terminal buffer in it — and tasks list runs in CI, where output is retained, shipped to log aggregators, and public on an open-source repository. So the body is something you ask for, once, about one task. --json still carries descriptionPreview, because --json is the API's own payload and filtering it would make this CLI's output a different contract from the endpoint it reports.

tasks update --description-file REPLACES THE WHOLE BODY, and the previous one is not recoverable. There is no confirmation and no undo. It is the sharpest edge on this surface and it is written down rather than guarded, because the guard does not belong here: /v1 has no read-modify-write for a description, and a CLI that invented one would be promising a guarantee it cannot keep. If it ever earns a real guard, that guard is an expectedUpdatedAt on the endpoint — the same one tasks update already takes for the task itself.

Read the body first if you are not certain what you are replacing:

ctask get ORA-12 --description > before.md

Two writers, one task. tasks update takes --expect-updated-at, the updatedAt you last read. If somebody wrote to the task in between, the change is refused with exit 3 rather than applied over theirs. Without it the last write wins, which is right for a caller with no prior read to be stale.

UPDATED=$(ctask get ORA-12 --json | jq .updatedAt)
ctask update ORA-12 --title "…" --expect-updated-at "$UPDATED"

What is not here yet. Attachments, a task's activity history, and the implementation plans and session logs agents write. The last of those is deferred deliberately rather than pending: their visibility is per-user, so an API key could only ever see the team-shared ones, and a view that quietly returns fewer rows than the desktop shows is worse than no view.

Output, exit codes, CI

  • --json prints one machine-readable JSON document on stdout, in the API's own envelope: { data, meta }, meta.requestId included. List commands carry meta.nextCursor so scripts page exactly like API callers — copy it until it is null, never count rows; a page can hold fewer than --limit results and still have a next page.
  • Errors always go to stderr, with the request id — quote it in support — so --json stdout stays parseable even on failure.
  • Color only on a TTY, and never when NO_COLOR is set. Nothing prompts without a TTY: piping a description with --description-file - on a terminal is refused rather than left to hang.
  • Exit codes are a contract: 0 done · 2 couldn't do it, try again — a 5xx, a timeout, rate limiting · 3 a conflict a person must resolve · 4 you have to change something — auth, configuration, or the request itself.

There is no exit 1. That code means "the thing under test is broken", which is a verdict — QA reports it about an app, and Tasks has nothing to say about it, because a task cannot be broken. Nothing in this package can produce it: commands are typed against an exit union that excludes 1, so a command trying to return one does not compile.

2 is retryable and 4 is not. A 5xx, a timeout or rate limiting is 2, and running the step again may work. A missing, malformed or under-scoped key is 4, and only new configuration fixes it — a CI step that retried on 4 would be retrying a key that will never start working.

A malformed request, an unknown id, a stale cursor and an oversized body are 4 as well. They are not your credential's fault, but the exit code is not a category label — it is an instruction, and 2 says run me again. tasks get ORA-99999 returns the same answer forever, so anything that cannot change without you changing it belongs on 4. 402 stays on 2, because credit arrives without you doing anything.