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

@markbennett/tang

v0.0.1

Published

A simple CLI for Tangled.org. Inspired by GitHub CLI, and usable by humans and AI.

Readme

tang

A CLI for Tangled.org — manage issues and repository context from the terminal. Designed to be usable by both humans and AI agents.

Installation

npm install -g @markbennett/tang

Quick Start

# Authenticate with your Tangled PDS handle and an App Password
tang auth login

# From inside a git repo cloned from tangled.org:
tang issue list
tang issue create "Bug: something is broken" --body "Detailed description"
tang issue view 1
tang issue close 1

# SSH key management
tang ssh-key add ~/.ssh/id_ed25519.pub

Commands

| Command | Description | | :--- | :--- | | tang auth login | Authenticate with your PDS handle and App Password | | tang auth logout | Log out and clear stored session | | tang issue list | List issues for the current repo | | tang issue create <title> | Create a new issue | | tang issue view <n> | View an issue | | tang issue close <n> | Close an issue | | tang issue reopen <n> | Reopen an issue | | tang ssh-key add <path> | Upload a public SSH key to your account | | tang context | Show resolved repo context (DID, handle, name) | | tang config | View or set CLI configuration |

Most commands accept --json [fields] for machine-readable output, useful for scripting and LLM integrations.


Architecture & Implementation Notes

Goal: Create a context-aware CLI for tangled.org that bridges the gap between the AT Protocol (XRPC) and standard Git.

Philosophy: Follow the GitHub CLI (gh) standard: act as a wrapper that creates a seamless experience where the API and local Git repo feel like one unified tool.

Prior Art Analysis: GitHub CLI (gh) vs. Tangled CLI

| Feature | GitHub CLI (gh) Approach | Tangled CLI Strategy | | :------------- | :--------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------- | | Context | Infers repo from .git/config remote URL. | Must-Have: Parse .git/config to resolve did:plc:... from the remote URL. | | Auth | Stores oauth token; acts as a git-credential-helper. | Plan: Store AT Proto session; inject auth headers into git operations if possible, or manage SSH keys via API. | | Output | TTY = Tables. Pipe = Text. --json = Structured. | Plan: Use is-interactive check. Default to "Human Mode". Force "Machine Mode" via flags. | | Filtering | --json name,url (filters fields). | Plan: Support basic --json flag first. Add field filtering (--json "cloneUrl,did") to save LLM context window tokens. | | Extensions | Allows custom subcommands. | Out of Scope for V1. |

High-Level Architecture (Refined)

The CLI acts as a "Context Engine" before it even hits the API. graph TD User[User / LLM] -->|Command| CLI

`subgraph "Context Engine"`
    `Git[Local .git/config] -->|Read Remote| Resolver[Context Resolver]`
    `Resolver -->|Inferred DID| Payload`
`end`

`subgraph "Execution"`
    `Payload -->|XRPC Request| API[Tangled AppView]`
    `Payload -->|Git Command| Shell[Git Shell]`
`end`

`API --> Output`
`Shell --> Output`

Tech Stack (TypeScript)

| Component | Library | Purpose | | :---------------- | :---------------------- | :--------------------------------------------------------------------------------------------- | | Framework | commander | CLI routing and command parsing (e.g., tangled repo create). | | API Client | @atproto/api | Official AT Protocol XRPC client, session management, and record operations. | | Lexicon Tools | @atproto/lexicon | Schema validation for custom Tangled.org lexicons (e.g., sh.tangled.publicKey). | | Git Context | git-url-parse | Parses remote URLs to extract the Tangled DID/NSID from .git/config. | | Git Ops | simple-git | Wraps local git operations safely. | | Validation | zod | Input validation and schema generation for LLMs. | | Interactivity | @inquirer/prompts | Modern, user-friendly prompts for interactive flows. | | Formatting | cli-table3 | Pretty tables for "Human Mode" output (following gh CLI patterns). | | OS Keychain | @napi-rs/keyring | Cross-platform secure storage for AT Protocol session tokens (macOS, Windows, Linux). | | TypeScript | tsx | Fast TypeScript execution for development and testing. |

Agent Integration (The "LLM Friendly" Layer)

To make this tool accessible to Claude Code/Gemini, we adopt gh's best patterns:

Rule 1: Context is King

LLMs often hallucinate repo IDs.

  • Design: If the user/LLM runs tangled issue list inside a folder, do not ask for the repo DID. Infer it.
  • Fallback: Only error if no git remote is found.

Rule 2: Precision JSON (--json <fields>)

LLMs have token limits. Returning a 50KB repo object is wasteful.

  • Feature: tangled repo view --json name,cloneUrl,description
  • Implementation: Use lodash/pick to filter the API response before printing to stdout.

Rule 3: Fail Fast, Fail Loud

LLMs can't read error messages buried in HTML or long stack traces. Provide a --no-input flag that forces the CLI to error if it can't resolve context or if required flags are missing.

Rule 4: Flexible Input for Issue Bodies

Following gh's pattern, tangled issue create will support various ways to provide the issue body, making it LLM-friendly and flexible for scripting. It will accept:

  • --body "Text" or -b "Text" for a direct string.
  • --body-file ./file.md or -F ./file.md to read from a file.
  • --body-file - or -F - to read from standard input (stdin).

Summary of Improvements

  • Context Inference: This is the "killer feature" of gh that we are copying. It makes the tool usable for humans and safer for LLMs (less typing = fewer errors).
  • Filtered JSON: Saves tokens for LLM context windows.
  • Git Config Integration: Treats the local .git folder as a database of configuration, reducing the need for environment variables or complex flags.
  • Flexible Issue Body Input: Improves usability for both humans and LLMs by allowing diverse input methods for issue descriptions.

Examples Tangled CLI Usage

tangled auth login (opens a browser for auth)
tangled repo create my-new-repo
cd my-new-repo
tangled issue create "Bug: Something is broken" --body "Detailed description of the bug here."
echo "Another bug description from stdin." | tangled issue create "Bug: From stdin" --body-file -
tangled issue list --json "id,title"
tangled pr create --base main --head my-feature --title "Add new feature" --body-file ./pr_description.md
tangled pr view 123
tangled pr comment 123 --body "Looks good, small change needed."

Basic Commands

Basic commands include auth, key management, repo creation, issue management, and pull request management.

tangled auth login

  • Logs in the user, ideally through a web browser flow for security. tangled auth logout
  • Logs out the user, clearing the session. tangled ssh-key add <public-key-path>
  • Uploads the provided public SSH key to the user's tangled.org account via the API. tangled ssh-key verify
  • Verifies that the user's SSH key is correctly set up and can authenticate with tangled.org. Returns the associated DID and handle if successful. tangled repo create <repo-name>
  • Creates a new repository under the user's account. tangled repo view [--json <fields>]
  • Displays details about the current repository. If --json is provided, outputs only the specified fields in JSON format. tangled issue create "<title>" [--body "<body>" | --body-file <file> | -F -]
  • Creates a new issue in the current repository with the given title and optional body, which can be provided via flag, file, or stdin. tangled pr create --base <base-branch> --head <head-branch> --title <title> [--body <body> | --body-file <file> | -F -]
  • Creates a new pull request in the current repository from a head branch to a base branch. tangled pr list [--json <fields>]
  • Lists pull requests for the current repository. tangled pr view <id> [--json <fields>]
  • Displays detailed information about a specific pull request, including comments. tangled pr comment <id> [--body <body> | --body-file <file> | -F -]
  • Adds a comment to a pull request. tangled pr review <id> --comment <comment> [--approve | --request-changes]
  • Submits a review for a pull request, with optional approval or request for changes.

Design Decisions & Outstanding Issues

This section documents key design decisions and tracks outstanding architectural questions.

(Resolved) SSH Key Management (gh Compatibility)

  • Original Question: How does gh manage SSH keys, and can we follow that pattern?
  • Resolution: Analysis shows that gh does not manage private keys. It facilitates uploading the user's public key to their GitHub account. The local SSH agent handles the private key.
  • Our Approach: The tangled ssh-key add command follows this exact pattern. It provides a user-friendly way to upload a public key to tangled.org. This resolves the core of this issue, as it is compatible with external key managers like 1Password's SSH agent.

(Decided) Secure Session Storage

  • Original Question: How should we securely store the AT Proto session token?
  • Resolution: Storing sensitive tokens in plaintext files is not secure.
  • Our Approach: The CLI will use the operating system's native keychain for secure storage (e.g., macOS Keychain, Windows Credential Manager, or Secret Service on Linux). A library like keytar will be used to abstract the platform differences.

(Decided) Configuration Resolution Order

  • Original Question: How should settings be resolved from different sources?
  • Resolution: A clear precedence order is necessary.
  • Our Approach: The CLI will resolve settings in the following order of precedence (highest first):
    1. Command-line flags (e.g., --repo-did ...)
    2. Environment variables (e.g., TANGLED_REPO_DID=...)
    3. Project-specific config file (e.g., .tangled/config.yml in the current directory)
    4. Global user config file (e.g., ~/.config/tangled/config.yml)

(Decided for V1) Authentication Flow: App Passwords (PDS)

  • Original Question: Can we allow auth through a web browser?
  • Resolution: For the initial version, the CLI will use App Passwords for authentication. This is the standard and simplest method for third-party AT Protocol clients and aligns with existing practices.
  • tangled auth login Flow: When running tangled auth login, the CLI will prompt the user for their PDS handle (e.g., @mark.bsky.social) and an App Password.
  • Generating an App Password: Users typically generate App Passwords from their PDS's settings (e.g., in the official Bluesky app under "Settings -> App Passwords", or on their self-hosted PDS web interface). The CLI does not generate app passwords.
  • Session Management: The session established is with the user's PDS, and this authenticated session is then used to interact with tangled.org's App View/Service.
  • OAuth Support: Implementing a web-based OAuth flow (similar to gh's approach) is more complex and not a standard part of the AT Protocol client authentication flow. This approach is deferred for future consideration.

Future Expansion Opportunities

The analysis of the tangled.org API revealed a rich set of features that are not yet part of the initial CLI plan but represent significant opportunities for future expansion. These include:

  • CI/CD Pipelines: Commands to view pipeline status and manage CI/CD jobs.
  • Repository Secrets: A dedicated command set for managing CI/CD secrets within a repository (tangled repo secret ...).
  • Advanced Git Operations: Commands to interact with the commit log, diffs, branches, and tags directly via the API, augmenting local git commands.
  • Social & Feed Interactions: Commands for starring repositories, reacting to feed items, and managing the user's social graph (following/unfollowing).
  • Label Management: Commands to create, apply, and remove labels from issues and pull requests.
  • Collaboration: Commands to manage repository collaborators.
  • Fork Management: Commands for forking repositories and managing the sync status of forks.
  • Reactions: Commands to add and remove reactions on issues, pull requests, and comments.
  • Commenting on Issues: Commands to add comments to issues.

Task Management

Tasks are tracked in the Tangled issue tracker. Use tangled issue list or tangled issue view <n> to browse tasks.

Development

Prerequisites

  • Node.js 22.0.0 or higher (latest LTS)
  • npm (comes with Node.js)

Installation

Clone the repository and install dependencies:

npm install

Available Scripts

  • npm run dev - Run the CLI in development mode (with hot reload via tsx)
  • npm run build - Build TypeScript to JavaScript (output to dist/)
  • npm test - Run tests once
  • npm run test:watch - Run tests in watch mode
  • npm run test:coverage - Run tests with coverage report
  • npm run lint - Check code with Biome linter
  • npm run lint:fix - Auto-fix linting issues
  • npm run format - Format code with Biome
  • npm run typecheck - Type check without building

Running Locally

When running commands against the development version, use npm run dev with the -- separator to pass arguments to the CLI:

# Run the CLI in development mode
npm run dev -- --version
npm run dev -- --help
npm run dev -- issue list
npm run dev -- issue create "My issue title" --body "Issue body"

# Build and run the production version
npm run build
node dist/index.js --version

# Install globally for local testing
npm link
tang --version
tang --help
npm unlink -g @markbennett/tang  # Unlink when done

Project Structure

tangled-cli/
├── src/
│   ├── index.ts          # Main CLI entry point
│   ├── commands/         # Command implementations
│   ├── lib/              # Core business logic
│   └── utils/            # Helper functions
├── tests/                # Test files
├── dist/                 # Build output (gitignored)
└── package.json          # Package configuration

Coding Guidelines

IMPORTANT: These guidelines must be followed for all code contributions.

Validation Functions Location

ALL validation logic belongs in src/utils/validation.ts

  • Use Zod schemas for all input validation
  • Boolean validation helpers (e.g., isValidHandle(), isValidTangledDid()) go in validation.ts
  • Never define validation functions in other files - import from validation.ts
  • Validation functions should return true/false or use Zod's safeParse() pattern

Example:

// ✅ CORRECT: validation.ts
export function isValidHandle(handle: string): boolean {
  return handleSchema.safeParse(handle).success;
}

// ❌ WRONG: Don't define validators in other files
// git.ts should import isValidHandle, not define it

Test Coverage Requirements

ALL code must have comprehensive test coverage

  • Every new feature requires tests in the corresponding tests/ directory
  • Commands must have test files (e.g., src/commands/foo.tstests/commands/foo.test.ts)
  • Utilities must have test files (e.g., src/utils/bar.tstests/utils/bar.test.ts)
  • Tests should cover:
    • Success cases (happy path)
    • Error cases (validation failures, network errors, etc.)
    • Edge cases (empty input, boundary values, etc.)
  • Aim for high test coverage - tests are not optional

Example test structure:

describe('MyFeature', () => {
  describe('successfulOperation', () => {
    it('should handle valid input', async () => { /* ... */ });
    it('should handle edge case', async () => { /* ... */ });
  });

  describe('errorHandling', () => {
    it('should reject invalid input', async () => { /* ... */ });
    it('should handle network errors', async () => { /* ... */ });
  });
});

Pull Request Checklist

Before submitting code, verify:

  • [ ] All validation functions are in validation.ts
  • [ ] Comprehensive tests are written and passing
  • [ ] TypeScript compilation passes (npm run typecheck)
  • [ ] Linting passes (npm run lint)
  • [ ] All tests pass (npm test)

Technology Stack

  • TypeScript 5.7.2 - Latest stable with strict mode enabled
  • Node.js 22+ - Latest LTS target
  • ES2023 - Latest stable ECMAScript target
  • Biome - Fast linter and formatter (replaces ESLint + Prettier)
  • Vitest - Fast unit test framework
  • Commander.js - CLI framework
  • tsx - Fast TypeScript execution for development