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

@telosfoundry/cli

v0.2.0

Published

Command-line client for the Telos REST API

Downloads

46

Readme

Telos CLI

Install the Telos command-line client globally:

npm install --global @telosfoundry/cli

Create an API key under Settings → API Keys, then authenticate and run a command:

export TELOS_API_KEY=telos_live_…
telos customer list

TELOS_API_URL defaults to https://www.telos-app.com and can be overridden for another Telos instance.

Attributing coding sessions to tasks

The collector reads local Codex and Claude Code session logs, keeps a marker of what you were working on, and uploads counters, timestamps, models and hashed identifiers under your own account. It never runs itself: no hook, no daemon, nothing on a timer.

telos track TEL-182        # start a marker (also linear:ENG-14, jira:PLT-3, unassigned)
telos switch TEL-183       # close the open marker, open another
telos stop                 # close the open marker without opening another
telos status               # open marker, sessions since your last submit, state file path
telos submit               # review the exact payload, then upload
telos collector off        # stop collecting; submit refuses until you turn it back on

telos submit builds and prints a complete locally hashed payload before any network request. The first submit, and any submit after the schema or collector version changes, requires consent before the CLI contacts Telos; --yes cannot bypass it. The CLI then prints the final server-keyed payload, prints it again after every allocation edit, and uploads only the exact object you confirm. --yes skips confirmation only for routine submits after that. --skip-unsupported leaves behind session logs from a client version this release cannot parse, which otherwise stop the whole submit.

No prompt, response, thinking text, tool payload, file path, environment value or credential can reach the payload. Session and response identifiers must have their provider's documented shape. They, your working directory and your branch are SHA-256 hashed locally before the server applies the workspace-keyed HMAC, so no raw identifier reaches Telos. Task and external-reference targets are bounded tokens and credential-like values are refused. Deleting a local log deletes nothing already uploaded — telos observed-evidence delete-self does that. Your own week is visible in the app under Time → My Time → Observed evidence, and nobody else can read it without a time-boxed grant an admin issues with a reason.

State lives in ~/.telos/collector/state.json, or under $XDG_STATE_HOME, or wherever TELOS_COLLECTOR_DIR points; telos status prints the path in use. The strict versioned file is atomically replaced with mode 0600. It keeps a byte-length and mtime watermark per session and always re-reads sessions that were open at the previous submit.

Mirror the Direction store

telos direction pull writes every published vision, strategy, product spec and context document into your repository as markdown with frontmatter, so a coding agent reads your direction from the filesystem instead of asking the API for it on every task.

The key

Create one in Telos under Settings → API Keys → New key with the grants direction:read, vision:read and strategy:read. A key without vision:read or strategy:read mirrors the product specs and context documents alone; the rest of the store is simply not there.

export TELOS_API_KEY=telos_live_…

TELOS_API_URL defaults to https://www.telos-app.com and points the mirror at another Telos instance.

Install the session-start hook

telos direction init

init writes the hook that keeps the mirror fresh into five places, creating each file if it is missing and leaving every other hook in it alone:

| Tool | File | | --- | --- | | Claude Code | .claude/settings.json | | Codex | .codex/hooks.json (trust it once: open Codex in the repo and run /hooks) | | Gemini | .gemini/settings.json | | Copilot | .github/hooks/telos-direction.json, plus ~/.copilot/hooks/telos-direction.json on this machine | | Cursor | .cursor/hooks.json |

The hook itself is npx -y @telosfoundry/cli direction sync, so the repository needs nothing installed. init also appends a short block to your repository's AGENTS.md telling an agent to read the mirror before it plans, and adds .telos/direction/ to .gitignore. Running it twice changes nothing. A file it cannot parse is skipped with the command to add by hand.

Claude Code runs the hook from the next session. Codex skips a repository's hooks until the project is trusted and the hook itself has been reviewed once in /hooks; it records trust against the hook's hash, so init never edits Codex's own config for you. Codex also ignores project hooks inside a git worktree. Verified on 2026-09-14 against Claude Code 2.1 and Codex 0.154: the Claude hook rebuilt a deleted mirror on session start; the Codex hook ran only after that one-time trust.

Copilot CLI 0.59 ran the hook from ~/.copilot/hooks/ and did not load the same file from the repository's .github/hooks/ in a headless session (github/copilot-cli issue 1730). So init also writes ~/.copilot/hooks/telos-direction.json on the machine it runs on, guarded to run only in a repository that carries .github/hooks/telos-direction.json; other repositories are untouched. Cursor's agent CLI ran the hook from .cursor/hooks.json. The Gemini file follows its documented format and has not been run here.

The four commands

telos direction sync                 # check, pull when the store moved, never fail
telos direction status               # 0 fresh, 1 stale, 2 no manifest, 3 other workspace
telos direction status --verify      # also diff every mirrored file against the store
telos direction pull                 # write .telos/direction/ and its manifest
telos direction pull --dir docs/direction
telos direction pull --reset         # wipe the directory and pull this workspace
telos direction pull --force-dir     # take over a directory that is not yet a mirror

sync is what the hook runs. It asks the store for one hash, pulls only when that hash moved, and exits 0 whatever goes wrong: an unreachable server, a refused key or a missing TELOS_API_KEY each print one line on stderr and let the session start. Only a mirror belonging to another workspace exits non-zero (3), because pulling over it would mix two organizations into one tree.

status is the same check without the pull. It reads one hash and compares it against the manifest, so it touches no file in the mirror and costs one request. --verify adds the full local walk: every mirrored file is hashed, strays and hand edits are reported, and the exit code is 1 when anything differs.

pull does the work. Files land at .telos/direction/<kind>/<ref>.md, for example .telos/direction/vision/vis-1.md. The path carries the ref alone, so renaming a document in Telos never moves its file. manifest.json next to them records the workspace, the pull time, the store's hash and each document's version, content hash and file hash; pull refetches only the documents whose version, hash, title or publish time moved, or whose file was edited or deleted locally.

The generated index

Every pull writes .telos/direction/AGENTS.md: where the documents came from and when, the vision and strategy to read first, then the product specs and context documents, each with its title, version and path, and the rule for telling a stale mirror from a fresh one. It is the one file to point an agent at. It is recorded in the manifest, so the fully-managed rule below keeps it rather than deleting it as a stray.

Without the CLI

The same data is on the Telos MCP server: get_direction_head returns the one workspace hash, list_direction_documents returns the rows and get_direction returns one document's body. That path works, and it is not the recommended one: every read spends model tokens on every session, and nothing makes an agent take it. The mirror is a file on disk that a hook keeps current, which is why it is enforced and the MCP path is not.

The directory is fully managed. Everything under it that the manifest does not account for is deleted on the next pull, including your own notes. Point --dir somewhere else before you put anything of your own next to the mirror, and git-ignore the directory: it is a cache a command reproduces, not source.

Because it deletes, the mirror refuses a --dir that is plainly not its own, and no flag lifts those refusals: the filesystem root, your home directory, the working directory or any parent of it, a symlink, a directory holding a .git entry, and any directory inside a repository other than the one your working directory is in. Inside your own repository the mirror is welcome anywhere below the root that is not a parent of your working directory, which is where the default .telos/direction sits. Those comparisons ask the filesystem which directory a path is rather than reading its name, so a differently spelled or short-named parent of your working directory is refused as the same directory, and two checkouts that differ only in case on a case-sensitive volume stay two. --force-dir lifts one refusal and only one: a directory that already holds files and no manifest.json this CLI wrote.

The mirror does not follow symlinks. Both commands plan before they act: they name every path the run may touch (each document and its temporary file, kept documents included, every deletion, manifest.json and its temporary file) and walk each one a directory at a time from the mirror root down, requiring every planned path to be absent or a regular file. A symlink or an obstacle anywhere on any of those paths stops the command before it fetches anything, deletes anything or wipes anything, status and --reset included. pull then downloads every changed document, walks the whole plan again, and only then writes, and each write and each deletion walks its own path once more immediately before the syscall that begins it. The rename that finishes a write is not re-walked separately, which the threat model below covers.

What this defends against. The mirror defends against a pre-existing symlink, misconfiguration or a malicious server; it does not defend against a concurrent local process that swaps symlinks between two of its own syscalls. Node's fs exposes no openat/O_NOFOLLOW-relative primitives, so a race-free implementation is not available in this runtime, and on the single-user developer machine the CLI is built for, a process with that power already owns the checkout; the mirror is not a boundary between users. Every guard in the mirror is therefore "checked immediately before use", not "atomic with use".

A symlink somewhere else under the mirror is not the mirror's business: it is reported on stderr and left alone, and it does not make status --verify stale. That is the one case where status prints a complaint and still exits 0, so the hook does not loop on a link the mirror declines to delete. --reset is the exception: it removes the whole directory, so such a link goes with it. The link is unlinked, whatever it pointed at is left alone, and the command says which links it removed.

Two things the mirror cannot see: a cloned volume that reports the same serial and file ids as another one looks like the same volume to every program on the machine, and a bind mount of your own files into the mirror on the same device looks like an ordinary directory. Do not mount anything into the mirror. A mount that reports a different device is refused rather than walked into.

The preflight is all or nothing, the apply is not: if the filesystem fights back midway through writing (a full disk, a permission change), some documents may be newer than the manifest. The next pull sees the hash mismatch and repairs them.

A key from another workspace refuses rather than mixing two organizations into one tree, and --reset is the way to switch.

License

MIT © Telos Foundry ApS