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

workctl

v0.2.1

Published

Unified CLI for task management across providers (ClickUp, Jira, etc.)

Readme

workctl

Unified CLI for task management across providers. One interface, multiple backends.

Currently supports ClickUp, with Jira and others on the roadmap. Designed for two audiences: developers working from the terminal, and AI agents / CI pipelines consuming structured JSON.

Table of Contents

Installation

npm install -g workctl

Requires Node.js >= 20.

Configuration

Interactive setup

workctl config init

The prompts guide you through:

  1. Generating an API token at https://app.clickup.com/settings/integrations/api
  2. Finding your Workspace ID at https://app.clickup.com/settings/workspace (the last number in the URL)

Configuration is stored in ~/.config/workctl/config.json (mode 0600).

Non-interactive setup

For CI or agent environments:

workctl config init --api-key pk_xxx --team-id 12345 --format json

Alternatively, skip the config file entirely and run with environment variables only.

Environment variables

Env vars always take precedence over file values:

| Variable | Purpose | |----------|---------| | WORKCTL_CLICKUP_API_KEY | API token | | WORKCTL_CLICKUP_TEAM_ID | Workspace ID | | WORKCTL_PROVIDER | Provider name (default: clickup) | | WORKCTL_PROFILE | Profile from the global config to apply (overrides .workctl.json's profile) |

With WORKCTL_CLICKUP_API_KEY and WORKCTL_CLICKUP_TEAM_ID set, no config file is needed.

Profiles

The global config supports a profiles map for working across multiple workspaces or clients:

{
  "provider": "clickup",
  "clickup": { "apiKey": "pk_xxx", "teamId": "111" },
  "profiles": {
    "acme": {
      "clickup": { "teamId": "222" },
      "defaults": { "listId": "list-acme" },
      "statusShortcuts": { "done": "shipped" }
    }
  }
}

A profile overlays the base config: any field it defines wins over the global value. Select one via .workctl.json ("profile": "acme") or the WORKCTL_PROFILE env var (which beats the repo file).

Per-repo config (.workctl.json)

Drop a .workctl.json at your repo root. It is discovered walking up from the current directory, stopping at the .git boundary:

{
  "profile": "acme",
  "defaults": { "listId": "list456", "branchPrefix": "feat" },
  "statusShortcuts": { "done": "shipped" }
}

Rules:

  • Credentials are rejected in .workctl.json. API keys live only in the global config.
  • Precedence (highest first): env vars > .workctl.json > referenced profile > global config.
  • With defaults.listId set, task list and task create no longer need --list.

Command Reference

All commands accept --format json for structured output.

| Command | Description | |---------|-------------| | task search | Search tasks across the entire workspace | | task mine | List tasks assigned to you | | task list --list <ID> | List tasks from a specific list | | task view [ID] | View task details; --tree includes subtasks | | task create <NAME> --list <ID> | Create a task; --if-not-exists for idempotency, --parent for subtasks | | task update <ID> | Update status, priority, name, description, tags, due date, custom fields | | task start [ID] | Move a task to the in-progress status of its list | | task done [ID] | Move a task to the done status of its list | | task branch <ID> | Create and switch to a git branch named after the task | | task pr-link [ID] | Comment the current branch's PR URL on the task | | task comments <ID> | List comments of a task | | task comment <ID> <TEXT> | Add a comment to a task | | task move <ID> --to-list <ID> | Move a task to a different list | | task delete <ID> | Delete a task | | task bulk | Bulk update tasks matching search filters; --dry-run to preview | | workspace spaces | List spaces in the workspace | | workspace lists <SPACE_ID> | List task lists in a space | | list statuses <LIST_ID> | Show the valid statuses of a list | | config init | Configure API keys and provider | | introspect | Show the full API contract (for agents/tooling) |

Commands with [ID] accept an optional task ID: when omitted, the ID is derived from the current git branch (see Git bridge).

Working with Tasks

Task IDs

All commands accept both internal IDs (abc123) and custom IDs (DEV-123). Custom IDs are auto-detected.

The literal me resolves to your user ID wherever an assignee is accepted:

workctl task mine --status "in progress"
workctl task search --assignee me --format json

Git bridge

task branch creates a branch named <prefix>/<id>-<slug> from the task name and switches to it. On such a branch, view, start, done and pr-link no longer need an explicit task ID:

workctl task branch DEV-123          # -> feat/DEV-123-fix-login-flow
workctl task start                   # moves DEV-123 to in-progress
gh pr create && workctl task pr-link # comments the PR URL on DEV-123
workctl task done                    # moves DEV-123 to done

Prefix resolution: --prefix flag > defaults.branchPrefix in config or .workctl.json > feat.

task pr-link detects the PR of the current branch via the gh CLI; pass --url <URL> to skip detection (useful in CI or without GitHub).

Status shortcuts

task start / task done resolve the right status per list: done picks the first done-type status, start the first custom-type status by order. Lists with several custom statuses can make start ambiguous — pin it explicitly with statusShortcuts in the config or .workctl.json:

{ "statusShortcuts": { "start": "in development", "done": "shipped" } }

Inspect a list's statuses with workctl list statuses <LIST_ID>.

Custom fields

task view shows custom fields with values; JSON output includes them as customFields. Dropdown and label fields are resolved to their option names on read.

Set fields with --field "Name=value" (repeatable). Field names are case-insensitive; dropdown/labels accept option names (labels take comma-separated values); numbers, dates (ISO) and checkboxes (true/false) are coerced automatically:

workctl task update DEV-123 --field "Severity=high" --field "Env=staging"
workctl task update DEV-123 --field "Areas=backend,infra"

Filter search results by field value (applied client-side on the fetched pages — combine with --all for workspace-wide filtering):

workctl task search --status open --field "Sprint=12" --all --format json

Unknown field or option names fail with the list of available ones.

Subtasks

Create a subtask with --parent; inspect a task's direct subtasks with --tree:

workctl task create "Write tests" --list abc123 --parent DEV-123
workctl task view DEV-123 --tree

In JSON output, --tree adds a subtasks array to the task object.

Idempotent creation

--if-not-exists skips creation when an open task with the same name (case-insensitive, exact match) already exists in the list, returning the existing task instead. Useful for agent loops and CI jobs that may retry:

workctl task create "Nightly report" --list abc123 --if-not-exists --format json

In JSON output the existing task carries "created": false.

Tags and due dates

workctl task create "Fix bug" --list abc123 --tags "bug,frontend" --due 2025-02-15
workctl task update DEV-123 --tags "bug"        # replaces the full tag set
workctl task update DEV-123 --clear-due
workctl task search --tag bug --due-before 2025-03-01

Note (ClickUp): the update endpoint ignores tags, so --tags diffs against the current tags via the tag endpoints — this costs one extra GET per update.

Markdown descriptions

Descriptions support full Markdown, inline or from a file:

workctl task create "Feature spec" --list abc123 --description-file ./spec.md
workctl task update DEV-123 --description-file ./updated-spec.md

In task view (human mode), Markdown is rendered for the terminal.

Search and pagination

task search supports repeatable filters (--status, --assignee, --tag), date ranges and closed-task inclusion:

workctl task search --created-after "2025-01-01" --updated-before "2025-03-31" --format json
workctl task search --assignee me --include-closed --format json

task list, task search and task mine accept --page <N> or --all (fetches every page, capped at 50 with a warning on stderr).

Bulk updates

task bulk combines search filters with a set of updates. Always preview first:

workctl task bulk --filter-status "in review" --set-status "done" --dry-run --format json
workctl task bulk --filter-status "in review" --set-status "done" --format json

Updates run with bounded concurrency. Failures do not abort the run: the result reports updated, taskIds and a failed array with per-task errors. There is no rollback — the underlying APIs are not transactional.

Moving tasks (ClickUp limitation)

ClickUp API v2 has no native "move task" endpoint. task move emulates it by adding the task to the destination list and removing it from the current one. This requires the "Tasks in Multiple Lists" ClickApp enabled in your Workspace, and ClickUp does not allow removing a task from its home list — in that case the task ends up in both lists and the command reports it.

workctl task move DEV-123 --to-list list456 --format json

Agent and Programmatic Use

Every command supports --format json:

  • stdout: JSON result data
  • stderr: JSON error objects ({ "error", "code", "message" })

Exit codes are stable and mapped to error codes:

| Exit code | Error code | Meaning | |-----------|------------|---------| | 0 | — | Success | | 1 | VALIDATION_ERROR / unknown | Invalid input or unexpected failure | | 2 | CONFIG_ERROR | Configuration missing or invalid | | 3 | AUTH_ERROR | Authentication failed | | 4 | PROVIDER_ERROR | Provider API error | | 5 | RATE_LIMIT | Rate limit exceeded (after automatic retries) |

The HTTP client retries on 429 (honoring Retry-After) and 5xx with exponential backoff, and preemptively throttles using the provider's rate-limit headers.

Get the full machine-readable API contract (commands, flags, output examples, error specs, workflows):

workctl introspect --format json

Generate a .cursor/rules/workctl.mdc file for LLM workspace context:

workctl introspect --emit-rules

Generate a Claude Code skill (auto-loaded when task-management context appears):

# User-global: ~/.claude/skills/workctl/SKILL.md
workctl introspect --emit-rules --target claude

# Custom directory (e.g. project-level or ctk skill distribution)
workctl introspect --emit-rules --target claude --out .claude/skills

To let Claude Code run workctl without permission prompts, add to .claude/settings.json:

{ "permissions": { "allow": ["Bash(workctl:*)"] } }

When installed via claude-master-toolkit, ctk install claude can invoke the --out form to place the skill alongside the rest of the ctk skill set.

Architecture

src/
  commands/         CLI commands (oclif)
  domain/           Models and ports (TaskProvider interface)
  providers/        Provider implementations (ClickUp, ...)
  shared/           Base command, errors, contract, formatters
  lib/              HTTP client, config service, git service, logger

Hexagonal architecture: commands depend on ports (interfaces), not implementations. Adding a new provider means implementing TaskProvider and registering it in the factory.

Development

git clone https://github.com/itboxful/workctl.git
cd workctl
npm install
npm run build
./bin/dev.js task search

Run tests:

npm test

License

MIT