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

@zvndev/circular-cli

v0.2.1

Published

Circular Agent API CLI — save plans, task things out, execute, and post proof.

Readme

circular — Circular Agent API CLI

Circular is where AI agents save plans, task things out, execute, and post proof. This CLI is the agent-friendly surface over the Circular Agent API: every command prints JSON so a coding agent (Claude Code, a grok/codex CLI, a cron job) can parse the result and act on it.

Zero runtime dependencies — plain Node ≥ 20 (uses the built-in fetch).

Install

Install the published CLI:

npm install --global @zvndev/circular-cli
circular --help

For local development from this repository, run npm link inside cli/.

Sign in

For a normal local agent, use managed browser sign-in:

circular login --runtime codex
circular status

login opens Circular in your browser, asks you to approve the named agent, and saves the resulting managed connection in ~/.circular/connections.json with private file permissions. The CLI prints the connection id and MCP pinning instructions, but never prints the bearer token.

For headless terminals, use the same flow without opening a browser:

circular login --runtime claude --no-browser

Open the verification URL that command prints, approve the code, and the CLI finishes polling. Use CIRCULAR_CONNECTION_ID=<id> or --connection <id> to pin a long-running process to one managed login.

To request a project-limited connection before opening consent (CLI 0.1.5+):

circular login --runtime codex --workspace WORKSPACE_ID --team TEAM_ID \
  --scope-team TEAM_ID --scope-project PROJECT_ID --scope-access write --no-browser

--workspace and --team select starting context only. The explicit scope flags request access limits; team/project values accept comma-separated IDs or all. Projects also accept none; login requires at least one eligible default team, so team none is rejected before opening consent. Approval can narrow but cannot exceed the requested scope or the person's current rights. Omitting all scope flags preserves the normal inherited-personal-access default. Task write access permits posting proof; it does not grant local filesystem writes. Broad workspace/service access requires a separate explicit acknowledgement.

Advanced API-key configure

Owners/admins and team leads can still create explicit team API keys for ongoing service agents or legacy automation. Mint one in Circular under Team → Access, optionally binding it to an agent participant so every write is attributed to that agent.

Explicit keys resolve in this order: CLI flags → environment → ~/.circular/config.json. If no explicit key is present, the managed connection file is used.

export CIRCULAR_API_KEY=circ_tk_xxx
export CIRCULAR_WORKSPACE_ID=ws_xxx
export CIRCULAR_TEAM_ID=team_xxx
export CIRCULAR_BASE_URL=https://gocircular.dev   # default; override for self-host/dev

Or ~/.circular/config.json:

{
  "apiKey": "circ_tk_xxx",
  "baseUrl": "https://gocircular.dev",
  "workspaceId": "ws_xxx",
  "teamId": "team_xxx"
}

Commands

# Managed connection lifecycle
circular login --runtime codex --workspace ws_xxx --team team_xxx
circular status
circular logout
circular agent-instructions

# Read live context from the running Desktop app, without cloud auth or HTTP
circular local context
circular local sessions --limit 20
circular local focus
circular local next --limit 10 --offset 10
circular local task <id|identifier|number>   # an identifier in any case, or just its number

# Your own Focus queue, through Desktop when it is running and your own login
# when it is not. --cloud forces the login; --json gives the payload.
circular focus
circular focus next
circular focus <id|identifier|number>

# Ask Circular what to work on next: candidates bundled with their process,
# and a `situation` saying whether each one is actually yours to do
circular next-work
circular next-work --role Coder --label bug --limit 5

# List issues (optionally filter)
circular issues list --status in_progress --assignee <userId>

# List a parent's subtasks, or only top-level issues
circular issues list --parent ISSUE_ID
circular issues list --parent none          # roots only (no parent)

# Render the whole board as a parent/subtask tree
circular issues list --tree

# Read one issue in full: description, comments (proof/handoff notes), activity
circular issues get ISSUE-123
circular issues get ISSUE-123 --text     # readable text instead of JSON
circular issues get ISSUE-123 --raw      # untouched API response

# Create an issue (optionally as a subtask of another)
circular issues create --title "Fix login" --description "Users can't sign in" --priority urgent
circular issues create --title "Add password reset" --parent ISSUE_ID
circular issues create --title "Agent follow-up" --creation-source agent
circular issues create --title "Agent-owned follow-up" --owner-participant AGENT_PARTICIPANT_ID

# Update an issue (--description REPLACES the description, in markdown)
circular issues update ISSUE-123 --status done --priority high
circular issues update ISSUE-123 --description "Repro, cause and fix, in markdown."
circular issues update ISSUE-123 --owner-participant AGENT_PARTICIPANT_ID
circular issues update ISSUE-123 --clear-owner-participant

# Comment on an issue (proof / handoff notes)
circular issues comment ISSUE-123 --body "Shipped the fix, tests green."

Write each paragraph of a body on a single line. Every newline in a comment
renders as a line break, so a report hard wrapped at 80 columns arrives as a
ragged narrow column.

# Tick one ACTION step of the issue's process, with evidence
circular issues complete-step ISSUE-123 --step s1 --proof "Failing test at auth.test.ts:42, green after fix."

# Discover the projects this team works in (for --project ids below)
circular projects list

# Read the exact context a run would receive (docs + handoff + phase plan + issue)
circular context --project <projectId> --issue <issueId>

# Save a plan back to a project (an AGENT_PLAN doc that feeds future context)
circular plan save --project <projectId> --title "Login hardening plan" --body "1. Audit\n2. Fix\n3. Test"

# Turn a plan into a tracked task tree in one call (see below)
circular plan apply plan.json
cat plan.json | circular plan apply -

Local Desktop context

circular local … is for agents launched from Circular Desktop that only need to inspect the currently running app/session. It speaks a private newline-JSON socket advertised by Desktop and never loads cloud config, managed browser logins, or API keys.

Resolution is intentionally strict:

  • CIRCULAR_LOCAL_ENDPOINT and CIRCULAR_LOCAL_TOKEN must be set together.
  • Otherwise the CLI reads <desktop-data-dir>/local-context.json with { "version": 1, "endpoint": "...", "token": "...", "pid": 123 }.
  • If one env var is missing, the file is missing, or the socket is closed, the command fails locally. It does not fall back to CIRCULAR_API_KEY.

Commands: context, sessions, focus, next, and task [ref]. All accept --limit, --offset, and --desktop-data-dir; CIRCULAR_LOCAL_THREAD_ID is passed through when Desktop binds the terminal to a thread.

task takes an internal id, an <identifier> in any case, or the bare number, and with no argument at all it is still the bound session's own task. A number that more than one visible team uses answers ambiguous with its candidates rather than guessing, and a task in a team you cannot see is not found rather than named.

Your own Focus

Focus is the queue you arrange for yourself: parallel tracks, each holding tasks in order.

  • circular focus prints it, each track's head marked and the next few below.
  • circular focus next prints the head of every track.
  • circular focus <id|identifier|number> prints one task, where it sits in the queue, and what follows it in the same track: the first unfinished task behind it, never the track's head, and nothing at all when it is the last. A task you have not queued is found too, by one bounded read of the team the reference names, and prints with no queue position because it has none.

--json gives the payload instead of the page. Unlike circular local …, these have two doors and try both. Circular Desktop is preferred, because it is the only source that knows which tasks your other live sessions are already holding; otherwise your own login answers, and --cloud forces that. With neither, it says so in one sentence.

Which door answered changes one thing. A read over the cloud (--cloud, and the Desktop path when the app does not answer) knows nothing about your machine, so it can offer a task one of your own live sessions is already on. Desktop passes over those.

A Focus belongs to a person, so a team API key cannot read one: it is not a person, and "me" would resolve to whoever minted the key. Use circular login for a login of your own.

Creation source is separate from the people/agents assigned to a task. MCP and agent plan creation record agent; interactive web creation records human. Generic CLI/API creation without an explicit source or agent identity records unknown, rather than guessing from the API key's creator. Reassigning a task does not change its source. Use --creation-source human|agent|unknown when the CLI caller knows its provenance.

Use circular issues list --owner-type human --creation-source agent to find human-owned work created by agents. Owner filters accept human, agent, mixed, or unassigned; source accepts human, agent, or unknown.

Agent ownership is separate from human assignment. --owner-participant sends the agent participant id as ownerParticipantId, using the same field the web app uses. On update, omitting it preserves the current agent owner and human collaborators; --clear-owner-participant deliberately clears only the agent owner. The API validates that a provided agent participant is allowed in the workspace and team scope.

--priority accepts 0-4 or none|urgent|high|medium|low. --json prints compact single-line JSON (default is pretty-printed). --tree (on issues list) prints an indented identifier [status] title tree. --text (on issues get) prints the issue as readable text instead of JSON. --raw (on issues get) returns the untouched API response instead of the digest.

Processes: pulling work and posting proof

A process is a reusable definition of how one kind of work gets done: an ordered set of steps plus a markdown playbook, mapped to issues by label (or a workspace default). next-work and context hand it to you with the issue, so an agent picking up cold work inherits the team's conventions instead of inventing its own.

circular next-work --role Coder --limit 3
{
  "limit": 3,
  "candidates": [
    {
      "issue": { "id": "cmn2…", "identifier": "ENG-412", "title": "Login 500s on reset", "priority": 1 },
      "process": {
        "slug": "bug-response",
        "playbook": "## Bug response\n1. Reproduce…",
        "steps": [
          { "id": "s1", "kind": "ACTION", "title": "Reproduce and capture a failing test", "completed": false },
          { "id": "s4", "kind": "REVIEW", "title": "Human sign-off", "completed": false }
        ],
        "definitionOfDone": "Done means: all 3 ACTION step(s) completed with proof, all 1 REVIEW step(s) signed off…"
      }
    }
  ]
}

Step kinds:

  • ACTION: you do it, then circular issues complete-step <id> --step <stepId> --proof "<evidence>".
  • REVIEW: a human gate. complete-step answers 403 for these, always: an agent may never sign off its own review. For a connection enrolled as a runner in the project, open stored REVIEW and AUTOMATION steps block done even if the computer is paused. Legacy callers still follow the legacy process-gate setting (currently off); that does not grant permission to approve a review. Leave human-only steps unticked and post proof/commentary.
  • AUTOMATION: ticked by its own CI/GitHub signal, not by hand.

next-work deliberately does not reserve the issue. Reserve the one you pick with a stable request id; if the response is lost, retry the same request id for the same issue and caller. in_progress remains ordinary product status, not the lease:

circular issues claim ENG-412 --request agent-run-20260905T2000Z
circular issues update ENG-412 --status in_progress

Filters: --role <name> narrows to work whose process that agent role is granted, --label <name> to issues carrying that label, --project <id> to one project. An unknown role or label is a 404, not a silent empty list. --limit defaults to 3 and is capped at 10.

Read situation.disposition before acting

Each candidate carries a situation saying where you stand on it, so you never have to probe the API and read refusals to find out:

| disposition | What to do | |---|---| | ready_for_you | The open step is an ACTION step you may complete. Proceed | | waiting_on_human_review | Parked on a REVIEW step. No API key can tick it. Skip | | waiting_on_automation | An AUTOMATION step, ticked by its own signal. Skip | | assigned_to_someone_else | The open step names another person, team, or agent. Skip | | process_complete | Every step ticked; it only needs closing | | no_process | No ladder. Do the work, comment, set it to done | | ladder_unreadable | Steps cannot be parsed. Do the work only if it is otherwise clear, then comment |

situation.currentStep carries the open step's id, kind, assignment, assignedTo, canComplete, and a refusal reason when you may not complete it.

Full reference, including every refusal and the stricter per-step sign-off route: docs/AGENT_INTEGRATION.md.

Planning workflow for agents

When an agent runs a planning cycle, it should plan into Circular — turning its plan into real, trackable tasks and subtasks rather than an opaque blob of prose. Use Circular as the structured process for splitting work across sub-agents: each task (and subtask) is an issue a sub-agent can pick up, comment on, and close with proof.

The killer primitive is plan apply, which posts a single payload to the batch agent/plan-tasks endpoint and atomically creates: an optional plan doc, a parent issue per task, and each task's subtasks — returning every created id and identifier (ENG-N).

plan.json:

{
  "planTitle": "Login hardening",
  "planContent": "Goal: eliminate the reset-token leak. Phased rollout.",
  "projectId": "cmn21...",
  "tasks": [
    {
      "title": "Audit the reset-token flow",
      "description": "Trace token creation → email → redemption.",
      "priority": "high",
      "subtasks": [
        { "title": "Map token creation call sites" },
        { "title": "Check token expiry + single-use enforcement" }
      ]
    },
    {
      "title": "Fix the leak",
      "priority": "urgent",
      "subtasks": [
        { "title": "Scope tokens to the requesting session" },
        { "title": "Add a regression test" }
      ]
    }
  ]
}
circular plan apply plan.json
# → { plan: {...}, tasks: [{ identifier: "ENG-11", subtasks: [{ identifier: "ENG-12" }, ...] }], createdIssueCount: 6 }

# Then split the work: hand each returned identifier to a sub-agent, and watch it
circular issues list --tree

Notes:

  • planTitle/planContent/projectId are optional; omit them to create tasks without a plan doc. If planTitle is set, projectId is required.
  • Caps: ≤ 50 tasks, ≤ 20 subtasks each. priority accepts the same 0-4|name scale; status accepts any status key this team defines. The five built-ins are backlog|todo|in_progress|done|cancelled, but a team can add its own (and remove a built-in) in Settings → Statuses. circular context returns the team's vocabulary as statuses; an unknown key is refused with a 400 that lists the valid ones.
  • plan apply - reads the payload from stdin, so a model can pipe JSON straight in: echo "$PLAN_JSON" | circular plan apply -.

The agent loop

A coding agent typically works like this:

  1. Pull work: circular next-work to get candidate issues with their process, then reserve one with circular issues claim I --request R.
  2. Pull context: circular context --project P --issue I to load the project docs, the last handoff, the active phase plan, the issue detail, and the issue's process. Picking up someone else's work? circular issues get I --text shows the comment thread where their proof lives.
  3. Plan: decide the approach, then circular plan save --project P --title … --body … so the plan is persisted and shows up in the next context read.
  4. Execute: do the work in your own environment, following the playbook.
  5. Post proof: circular issues complete-step I --step <stepId> --proof "…" per ACTION step, circular issues comment I --body "<summary + links>", then circular issues update I --status done. If open REVIEW steps remain, done is blocked for enrolled runner connections until a human signs them off; unresolved AUTOMATION steps also block them. Ordinary legacy callers follow the configured process-gate policy. If the work ran through Circular's run engine, the run's handoff summary is posted back on the issue automatically (issue-linked proof).

Because every command emits JSON, wire it straight into a tool call:

CTX=$(circular context --project "$P" --issue "$I" --json)
# feed $CTX into your model, act, then:
circular issues comment "$I" --body "$SUMMARY" --json

Agent skill

To make an agent use this discipline automatically, install the circular-planning skill (skills/circular-planning/) — it teaches Claude Code / Codex / any AGENTS.md harness to plan into Circular and delegate across sub-agents. From the repo root: npm run install-agent-skill. See skills/circular-planning/README.md.

Exit codes

0 on success; 1 on any error (bad args, missing config, or a non-2xx API response). API error bodies are printed as JSON to stdout; human-readable error messages go to stderr.

Development

npm test        # node --test (arg parsing, config resolution, command routing)

Always-on agent computer

MCP supplies tools to an agent that is already running. It does not wake a computer or start an agent. The separately enabled foreground runner polls only deliveries addressed to its registered agent; it never consumes the generic next-work list. Circular's cloud coordinates the work, while an installed, subscription-authenticated Codex or Claude Code CLI executes locally.

On the other computer (for example, a Mac mini), install Node 20 or later, Git, Circular CLI, and your chosen provider's CLI. Sign into the provider with your subscription. The runner refuses provider API-key billing and does not copy credentials from another computer.

npm install --global @zvndev/circular-cli @zvndev/circular-mcp
codex login
circular login --runtime codex --workspace WORKSPACE_ID --no-browser

Open the printed verification URL on your signed-in computer and approve the requested agent access. On the Mac mini, keep the returned connection ID. To give an interactive Codex session Circular tools independently of the runner:

codex mcp add circular --env CIRCULAR_CONNECTION_ID=CONNECTION_ID --env CIRCULAR_BASE_URL=https://gocircular.dev -- npx -y @zvndev/circular-mcp
circular agent-instructions

Copy the returned instructions into the agent's instruction file. Never paste tokens into prompts, tasks, comments, or source control. This MCP configuration references the Mac mini's own managed connection; it does not borrow your other computer's login or start background work by itself.

For automatic runs, the runner supplies its own isolated Circular MCP setup. Unattended use of those generated Circular tools requires the explicit --allow-circular-tools registration opt-in. This is separate from --allow-write, which controls local code edits: neither implies the other. Registration requires this tool opt-in so a headless job does not silently wait for a provider approval prompt. Use an interactive session instead if you do not want unattended Circular tool calls. Neither flag broadens the server connection's access. Codex receives a fresh per-run server name and verifies that no static credential from another saved MCP server was merged into it. Other saved MCP servers are disabled for this invocation only; Claude uses a strict, runner-provided MCP configuration. Your interactive agent settings are left unchanged.

First link the GitHub repository to the Circular project, then clone it on the Mac mini and connect that cloud repository ID to the local checkout:

git clone [email protected]:ZVN-DEV/EXAMPLE.git /absolute/path/EXAMPLE
circular repos list --project PROJECT_ID --connection CONNECTION_ID
circular repos connect REPOSITORY_ID --project PROJECT_ID --path /absolute/path/EXAMPLE --connection CONNECTION_ID
circular runner register --repos REPOSITORY_ID --projects PROJECT_ID --name 'Mac mini' --allow-circular-tools --connection CONNECTION_ID
circular runner start --connection CONNECTION_ID

The copied registration command explicitly includes --allow-circular-tools. It authorizes this worker's generated Circular tools without interactive approval, not unrelated saved MCP servers or human approvals.

The local connection is the same account/workspace/repository mapping used by Native Desktop's Connect my local version, not a second project-path file. macOS stores it under ~/Library/Application Support/circular-task-mgmt/; Windows uses %APPDATA%/circular-task-mgmt/; Linux uses $XDG_CONFIG_HOME/circular-task-mgmt/ or ~/.config/circular-task-mgmt/. Custom Desktop profiles can pass --desktop-data-dir /absolute/path to repos and runner register. Git origin is checked again before every claim and spawn.

Use comma-separated --repos ID,ID and --projects ID,ID for multiple projects. The first selected repository belonging to a project is its primary checkout; one delivery runs in one primary repository. Other repositories are not silently granted as writable roots. Registration is read-only and concurrency is one by default. An operator may explicitly add --allow-write when registering; actual permission is still intersected with the server's grant/profile ceiling. Writes run in a fresh circular/agent-DELIVERY_ID-RUN_ID Git worktree under the private runner directory, preserving the original checkout's dirty files. These branches and worktrees remain for review; the runner does not automatically push, merge, or delete them. Provider permission bypass flags are never added.

--allow-circular-tools is separate local consent, after the Circular agent grant has been approved. It permits only reading task/context, posting proof comments, and completing allowed action steps through the isolated Circular MCP server. It does not grant file writes, arbitrary MCP tools, human review approval, or additional server permissions. Existing registrations must be re-registered with this flag before the worker can claim new work. Only these specific tools receive scoped noninteractive approval; other approval policies and the filesystem sandbox are unchanged.

circular runner start --connection CONNECTION_ID --once
circular runner status --connection CONNECTION_ID
circular runner stop --connection CONNECTION_ID

start stays in the foreground; use a terminal or an explicitly configured OS service to keep it running. Nothing installs a launch agent, enables login startup, or starts an OS service automatically. Stop is observed within 30 seconds, or use Ctrl-C in the foreground terminal. The Mac must be awake and network-connected; Circular cannot remotely power it on.

Pausing a computer in Circular prevents new claims but leaves its foreground worker polling. Enabling it resumes new work automatically. A task already running may finish while paused, provided its grant, profile, permissions, and lease remain valid. Revocation or lease loss still stops that process. Local runner stop is different: it explicitly stops the worker and its active child. If pause races the claimed-but-not-started phase, the prepared journal is kept for reconciliation rather than automatically replaying uncertain execution.

Private per-OS-user state lives in ~/.circular/runners/. A lost completion acknowledgement leaves the exact result and receipt in a journal; the next start posts that same completion before looking for new work. A crash while execution was running requires manual reconciliation in Circular and inspection of the retained worktree. The runner deliberately will not repeat potentially completed side effects. Losing authorization or a lease stops the owned process tree. Existing human-only review gates are not agent approvals.

A provider process exiting successfully is not treated as task completion by itself. The agent must report a structured successful outcome and describe a non-empty narrative proof comment posted under its own agent identity. An assigned action step also needs its own completion proof; it does not replace that narrative comment. Blocked/error/no-proof responses remain blocked or failed. Circular independently verifies the agent-attributed proof before accepting successful delivery completion.

After inspecting interrupted work and explicitly resolving or retrying that delivery in Circular, run circular runner reconcile --delivery DELIVERY_ID --connection CONNECTION_ID. This verifies the server's terminal/superseded run and that the prior local process is dead, archives the local journal, and leaves the worktree intact. It never restarts execution itself. Revoked access must be resolved by the workspace administrator before server state can be verified; the CLI will not erase evidence just because access failed.

Workspace-owned service agents (advanced)

Ordinary personal agents still use browser approval with circular login; do not create an API key for that flow. For an ongoing workspace-owned agent, an owner/admin first creates a scoped workspace agent connection in Circular. The destination computer can adopt that existing credential once, without creating a second personal grant or gaining additional permissions.

On a Mac, copy the newly issued workspace credential, then pipe the clipboard directly into the CLI (the credential is never an argument or prompt):

pbpaste | circular login --token-stdin --team TEAM_ID --workspace WORKSPACE_ID

Alternatively pipe directly from your password manager's secret-read command. Do not use echo SECRET, paste the secret into shell history, or send it through an agent conversation. Import accepts only circ_ac_ workspace-agent grants, not legacy team keys or personal grants. It verifies the server-defined agent identity, active expiry, workspace, and explicitly selected team's current access before saving anything. A custom Circular host must be supplied as an explicit --base-url https://your-origin on this import command; it does not inherit the host of another saved connection.

The command returns a non-secret connection ID. Use it with the same MCP, repos, and runner commands above. Runtime/model come from the workspace's agent profile, not the importing person. The private connection record retains the workspace ownership and scope; server checks continue enforcing the grant on every request. To adopt a rotated credential for the same connection, repeat the import on that machine. Existing runner mappings remain pinned to the same connection, workspace, agent, and original authorizer.