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

threadwire

v0.1.30

Published

Stream Codex, Claude, Kimi Code, and OpenCode worker progress to an explicit Telegram destination

Readme

Threadwire

Threadwire is a Node.js CLI that launches a Codex, Claude, Kimi, or OpenCode worker and either streams a concise, human-readable activity feed to one explicitly selected Telegram destination or writes a normalized result to an explicit local file target. The default Telegram feed includes the assistant's response prose, lifecycle outcomes, and diagnostics. Provider tool-status messages are disabled by default.

For the container-native webhook deployment, including its named-volume worktree, non-root Codex provider, Docker secrets, loopback TLS proxy, verification, and rollback path, see Container runtime. The legacy host launcher below remains supported and is separate from that deployment.

Relay-originated Codex writes are explicit and default off. --relay-write selects the optional root-owned isolated runtime and credential broker. The worker gets one writable task worktree, no upstream or Git credential, and no route except its run-scoped broker. Missing prerequisites fail before prompt or credential reads with no native fallback. The isolated runtime imposes no default full-run deadline: a healthy running worker is never stopped merely because time elapsed. An operator may set THREADWIRE_WORKER_TIMEOUT_MS (supervisor) and THREADWIRE_ISOLATED_RUNTIME_CLIENT_TIMEOUT_MS (client) to a positive millisecond value to enable one absolute preflight+run deadline; empty or unset means unlimited. Broker grants use a bounded lease that the supervisor renews while the run is active and that expires within one lease if the supervisor dies; unrelated safety timeouts (preflight slice, per-operation Docker/network calls, state collection, emergency cleanup) are unchanged. See Isolated provider runtime.

Run with npx

Threadwire requires Node.js 24 or newer. Run the published CLI without a global installation:

npx --yes threadwire@latest --help

npx --yes threadwire@latest run \
  --provider codex \
  --target telegram:-1001234567890:42 \
  --cwd /path/to/repository \
  --prompt 'Inspect the project.'

Provide THREADWIRE_TELEGRAM_BOT_TOKEN through a trusted environment or secret manager; do not put the token in the command line. Codex first uses a valid THREADWIRE_CODEX_BIN, then the first executable codex found by left-to-right Unix lookup in the supplied PATH; if no safe candidate is found, it runs the normal codex command. Relative and empty PATH entries resolve from the worker's --cwd. Candidates are canonically resolved and inspected before use; known Threadwire front doors such as /opt/data/bin/codex, including aliases to them, are rejected while lookup continues, preventing recursive relay. A stale override warns with the actual selected fallback. Use THREADWIRE_CODEX_BIN only for an intentional custom/container adapter. For Claude or OpenCode, use THREADWIRE_CLAUDE_BIN or THREADWIRE_OPENCODE_BIN respectively; those overrides must name direct provider executables, never Threadwire front-door shims.

To install the same commands globally instead:

npm install --global threadwire
threadwire --help

Usage

Use the local launcher. Install or refresh it after updating Threadwire with npm run install:local-launcher. It first validates the Threadwire-owned arguments with a token-free check, so a missing or malformed provider or target fails with Threadwire's own safe error before the dotenv is opened. Only for a valid invocation does it then read only TELEGRAM_BOT_TOKEN from the trusted /opt/data/.env, map it to THREADWIRE_TELEGRAM_BOT_TOKEN for Threadwire, and never source the wider dotenv. Threadwire never supplies routing defaults and never reads routing from a prompt or repository.

/opt/data/bin/threadwire run \
  --provider codex \
  --target telegram:-1001234567890:42 \
  --process-number 42 \
  --cwd /path/to/repository \
  --tool-messages \
  --prompt 'Inspect the project.' \
  -- --model example-model

The target has the form telegram:<chat-id>:<thread-id> for topics, telegram:<chat-id> for direct messages (DMs) and ordinary chats, or file:<absolute-path> for local no-message execution. A file target requires a normalized absolute file path, needs no Telegram token, creates the file exclusively with mode 0600, fsyncs it and its directory, and writes the exact same single normalized delegated_result record as stdout. It cannot be combined with --transcript. Telegram chat IDs and optional thread IDs keep their existing validation. --provider must be exactly one of codex, claude, kimi, or opencode. Malformed or missing provider or target arguments are hard failures (exit code 2) reported through Threadwire's normal error path before any provider is launched. --process-number accepts an explicit positive safe integer for automation; when omitted, Threadwire uses its launcher PID. Every Telegram message is labeled consistently, such as [P42] …, including chunked continuations.

--cwd is the complete workspace contract for every provider. It may name any caller-accessible directory, including a non-Git directory. Threadwire passes it unchanged to the native provider and performs no profile, repository, source-identity, task-binding, or root-allowlist lookup. --workspace-profile has been removed and is rejected; migrate invocations by replacing it with --cwd <directory>.

Provider tool-start and tool-finish events do not produce Telegram messages by default. Pass the boolean --tool-messages flag to opt in, as shown above. When enabled, each tool is one concise, silent status line rather than a pair of noisy start/finish notices: when a tool starts, Threadwire sends 🛠 [P42] Tool: <safe command or tool description> (for example 🛠 [P42] Tool: command — git status --short), and when that same tool finishes, it edits the original message in place so it begins instead — no second completion message is sent, and Telegram edits raise no notification. The command/description shows a safe CLI-style preview with credential-bearing values (tokens, passwords, keys, authorization/cookie forms, credentials in URLs) redacted and control characters stripped; only normalized Codex command-completion output may also be appended to that same edited status as a Telegram-native expandable HTML blockquote with the visible label Output →; it is credential-redacted, HTML-escaped, and Unicode-safe bounded. Stderr, reasoning, and every other raw provider result remain excluded. Use --max-output-length <positive-integer> to truncate only that preview Unicode-safely; omit the option for unlimited tool detail. A prompt may instead come from --prompt-file or piped stdin, and every source rejects blank/whitespace content. Arguments following -- pass to the selected provider, except output-stream and session options owned by Threadwire. Native Kimi uses the caller's compatible configuration. Threadwire maps its public --resume-session <exact-id> option to Kimi's native --session <exact-id> option and owns --prompt plus --output-format stream-json. The caller environment or image must provide kimi on PATH or set THREADWIRE_KIMI_BIN; a missing executable fails normally.

Threadwire directly spawns the structurally separate terminal adapters /opt/data/libexec/threadwire/codex, /opt/data/libexec/threadwire/claude, kimi resolved from PATH, or /opt/data/libexec/threadwire/opencode-local-fleet with an argv array and shell: false. These libexec adapters hold the real provider-CLI logic and are never on a worker's PATH, so relaying can never recurse back into the front-door shims. Each spawn also sets THREADWIRE_ACTIVE=1 in the provider child environment. The executable can be overridden per provider with THREADWIRE_CODEX_BIN, THREADWIRE_CLAUDE_BIN, THREADWIRE_KIMI_BIN, or THREADWIRE_OPENCODE_BIN for staged cutover and rollback. It does not impose a worker timeout. SIGINT and SIGTERM are forwarded to the worker as explicit cancellation. Terminal completion is explicit and provider-owned rather than derived only from process exit: native Kimi confirms a completed run with a final assistant response (assistant content without further tool calls) plus its session handoff record in the stream. Once both records are confirmed, Threadwire preserves the session continuation handle, terminates the attempt-owned provider process group (SIGTERM), and emits exactly one delegated_result. Success settles only once the entire owned group is gone: members that survive SIGTERM — including attempt-owned grandchildren — keep the grace-period escalation running and receive SIGKILL against the exact group before settlement, so no descendant is leaked even when the direct provider exits first. A provider that exits nonzero before its protocol confirms completion keeps its failure status, and long-running tool activity remains unbounded: there is no generic idle timeout, only caller cancellation or an explicit deadline. Parent SIGINT/SIGTERM is owned cancellation, not just forwarding: the signal reaches the exact attempt-owned group, surviving members are escalated to SIGKILL after the grace period, and settlement keeps the forwarded signal's exit status (143/130 on Linux) only after the owned tree is gone. Relay/consumer failure cleans up the same owned tree — even when the failure lands after the direct child closed and only descendants survive — and the worker runner also accepts an explicit AbortSignal: an abort terminates the exact attempt-owned group with the same grace/escalation and settles with the abort failure, never success. After any SIGKILL, settlement waits for bounded cleanup confirmation — the exact group is re-probed, or on platforms without process groups the direct child's close is required — and cleanup that cannot be confirmed within the bounded window settles as failure, never success; this confirmation bound is not an idle or tool-activity timeout.

For Codex in ordinary project images, the fixed structural path described above is only the preferred fallback after a valid override. When that adapter is not executable, Threadwire uses the first inspected safe codex candidate from PATH instead.

Provider front-door shims

/opt/data/bin/codex, /opt/data/bin/claude, and /opt/data/bin/opencode-local-fleet are Threadwire front-door relay shims. Install or refresh both them and their paired libexec adapters with npm run install:provider-shims; the installer generates all six scripts from the repo templates and never modifies runtime artifacts on its own. A worker invocation is routed through the /opt/data/bin/threadwire launcher so its activity streams to the caller's explicit Telegram destination; every non-worker mode runs the real provider CLI unchanged through the paired libexec adapter.

A trusted host controller can generate its launcher with an absolute, controller-only Telegram bot-token file:

node scripts/install-local-launcher.js /opt/data/bin/threadwire \
  --telegram-bot-token-file /run/secrets/threadwire_telegram_bot_token

After token-free argument validation, the launcher reads at most 8 KiB from a regular, non-symlink file that is not group/other-writable, exports THREADWIRE_TELEGRAM_BOT_TOKEN only to the Threadwire controller, and clears the file pointer. Threadwire's existing provider boundary removes the token and pointer before spawning any provider. The token file and value are never passed through Docker argv/environment, mounted or copied into the task container or source, added to prompts, or written to logs. Omitting the option preserves the existing TELEGRAM_BOT_TOKEN dotenv lookup.

The relay contract: the caller supplies THREADWIRE_TARGET (telegram:<chat-id> or telegram:<chat-id>:<thread-id>) and, optionally, THREADWIRE_PROCESS_NUMBER. The prompt arrives on a piped stdin; all native provider flags pass through after --. A positional prompt is never parsed. A missing THREADWIRE_TARGET fails closed (exit code 2) and a malformed one is rejected by the launcher's token-free preflight — the shim never invents a default destination and never silently downgrades a requested relay to a direct run. A shim relays only for a worker mode (codex exec …, opencode-local-fleet run …, or any non-interactive claude …); it drops the worker subcommand before relaying and Threadwire re-adds it around the prompt. Version and help queries, non-worker subcommands, interactive TTY sessions, and any invocation already inside a relayed run (THREADWIRE_ACTIVE=1, so nested provider workers stay local/native) run the real CLI directly through the libexec adapter.

Pass --resume-session <exact-provider-session-id> to continue a stored Codex, Claude, Kimi, or OpenCode session. Threadwire preserves the provider's native resume ordering and streaming options and never uses implicit latest-session behavior.

Pass --transcript <path> with a Telegram target to capture the exact normalized, caller-facing JSONL protocol written to run stdout. The file is created privately (mode 0600), must not already exist, and contains the same records in the same byte order as stdout. A file:<absolute-path> target provides this capture directly and therefore rejects a separate --transcript. Neither form contains provider JSONL, reasoning, tool payloads, prompts, stderr, or credentials. The result/transcript path and --activity-log path must not canonically alias; final-component symlinks and aliased parent directories are rejected during preflight before either output is opened.

--activity-log <path> is different: it retains its append contract and writes safe timestamped lifecycle facts—provider start (provider, child pid), available native session ID, throttled activity markers, structured health events (bounded retrying/blocked disposition with safe category), and exactly one terminal fact. It is local-only and never enters Telegram or normalized stdout.

Inspect a live or completed activity log with the read-only threadwire status --activity-log <absolute-path> command. It emits exactly one closed versioned JSON document with version, state (running/retrying/blocked/completed/failed/cancelled/unknown), provider, controllerPid, providerPid, continuationHandle, startedAt, lastActivityAt, quietForMs, health (or null), and terminal (or null). The command derives state from the file only, never opens it writable, never inspects or signals processes, and never claims stalled/dead from silence. PIDs are recorded facts with explicit non-authoritative semantics.

Provider stdout is decoded as JSONL with a finite 1 MiB UTF-8 byte limit for each pending unterminated record. Exceeding it rejects the run, removes listeners and signal handlers, and terminates the provider without parsing or rendering the oversized content.

For normal threadwire run execution, Threadwire stdout is the parent-model admission plane. It emits exactly one versioned terminal delegated_result JSON object and no progress records. The envelope contains a bounded, credential-redacted, control-normalized final conclusion when one was produced, structured terminal state and exit code, and the exact bounded provider session handle when available. Its closed schema can also represent concise blocker/decision requests, opaque artifact handles, commit/URL references, and a concise validation summary; current provider adapters do not infer these optional fields from prose. Unknown, nested, wrongly typed, cardinality-invalid, or oversized admission candidates fail closed. See Delegated-result protocol for the complete schema, limits, and caller obligations.

Scoped evidence artifacts are separate from both files above. Set the trusted operator setting THREADWIRE_EVIDENCE_ROOT for standalone runs; Telegram ingress uses its dedicated evidence volume automatically. CLI and ingress runs reserve separate normalized provider-result and raw prompt/provider-stream artifacts; CLI raw evidence also records final context metrics. A raw handle enters a normalized result only after the raw artifact is durable; if raw metrics append or finalization fails, the error remains visible while the completed provider result retains only its independently durable result handle. The result artifact carries a stable delivery identity and authenticated state, and ingress sends that result handle through the same bounded notice queue. Retrieve later with threadwire evidence read, inspect the per-run SQLite index with threadwire evidence inspect, or use the authenticated /evidence Telegram command with an explicit bounded selector. See Evidence artifacts for permissions, delivery states, quotas, retention, recovery, authorization, redaction, privacy, cleanup, and the inspect fixed-selector contract.

threadwire capacity is a read-only reporting command that probes live account capacity for authenticated Codex (codex app-server JSON-RPC account/rateLimits/read) and Kimi (GET https://api.kimi.com/coding/v1/usages with the installed OAuth credential), normalizes both into one closed short/long-window schema, and prints one deterministic reserve-gated admission selection as a single JSON document. It persists nothing, never prints tokens or account data, takes no session arguments, and does not change run provider selection; an external worker ledger consumes the report and owns pinning provider/model/session. See Capacity admission for the schema, tie-break, error taxonomy, and security boundary.

Telegram is the separate user-visible progress plane. Lifecycle notices, diagnostics, tool activity, and assistant streaming continue there independently; --tool-messages affects only Telegram. Execution-environment details, provider records and streams, lifecycle progress, diagnostics, tool names/arguments/details/output, stderr, prompts, narration/reasoning, and full transcripts never enter stdout. Threadwire's bounded error diagnostic remains on stderr. Help output is the sole non-run, human-readable stdout mode. This default is an intentional pre-1.0 protocol break from the former mixed Hermes JSONL stream.

The Telegram bot token is used only by Threadwire's notifier and both TELEGRAM_BOT_TOKEN and THREADWIRE_TELEGRAM_BOT_TOKEN are removed from every provider child environment. The three libexec adapters repeat that scrub as defense in depth. Other environment variables, including the providers' own authentication and normal process configuration, are preserved. Outbound Telegram fetch and response-body parsing share a 30-second deadline by default; set THREADWIRE_TELEGRAM_REQUEST_TIMEOUT_MS to a positive safe integer no greater than 2147483647 to override it.

A single trusted renderer is the only code allowed to enqueue Telegram notices. By default, parsed assistant text is forwarded in order with every nonblank rendered line labeled [P<n>] Assistant: ; no CLI flag is required. This preserves Markdown, code-block indentation, blank lines, and whitespace attached to nonblank content while preventing assistant text from imitating trusted activity on a later line. Streamed fenced JavaScript blocks (```js / ```javascript) are instead emitted as independently valid, escaped Telegram HTML code messages: the [P<n>] Assistant: label stays above the code block, and long blocks are Unicode-safe chunked without exposing raw fences. A short blank-only stream is suppressed at normal close. Because retention is bounded, a blank-only prefix longer than the buffer limit is emitted in oldest-first chunks while at most one limit's worth remains deferred; a later visible assistant character therefore still reconstructs the input exactly, but an indefinitely blank stream cannot be suppressed indefinitely. With --tool-messages, tool activity uses a single edit-in-place status line (silent 🛠 … on start, edited to begin on finish); without it, both the send and completion edit are suppressed. Worker start/completion/failure and warning/error diagnostics continue to use fixed labeled templates in either mode. Non-assistant provider fields—including summaries, tool names, metadata IDs, inputs, commands, stderr content, raw JSON, reasoning/thinking, tokens, and retry internals—are not forwarded. When tool messages are enabled, the sole provider-data exception is normalized Codex command-completion output: it is appended only to its original tool status edit as an escaped, bounded, expandable Telegram HTML blockquote after shared credential redaction.

Assistant deltas from all provider stream IDs share one ordered sentence-boundary buffer, preserving provider-event order. The buffer has a finite 16,384-character default: a continuously active punctuation-free stream emits and clears Unicode-safe fixed-size chunks instead of growing indefinitely. Structured events flush any earlier assistant tail, including retained leading whitespace, before their own fixed notice. Completed boundaries enter delivery without a deliberate batching delay; messages combine only when already naturally queued behind delivery. When Telegram briefly falls behind, Threadwire emits a fixed safe notice that the notifier saturated and then coalesces only eligible assistant progress until headroom returns; lifecycle, diagnostics, and tool activity remain ordered and non-droppable. Notices remain ordered, size-limited, paced, and retried conservatively when Telegram reports throttling or a transient failure. A provider result is admitted independently: exhausted delivery retries return a delivery failure without rerunning the provider or changing its completed normalized result.

The delivery queue has finite defaults of 100 pending notices and 256 KiB of pending UTF-8 text. Message length and capacity settings require positive safe integers; pacing settings require nonnegative safe integers. A notice larger than the byte limit or a limit-plus-one enqueue latches a terminal capacity error, discards queued (not already in-flight) notices, and rejects every later enqueue. Unicode chunks never split a surrogate pair, and every labeled continuation retains its complete process label. If the label cannot fit with content under a configured message length, delivery latches a terminal chunking error before sending. These rules make delivery loss visible and prevent slow or rate-limited transports from consuming unbounded memory. A persisted delivery_failed state means Threadwire received no successful response after the bounded attempts. A timeout or dropped response can be ambiguous, so Threadwire guarantees provider non-rerun but does not claim exactly-once Telegram display.

Development

The checked-in development container is the app service in compose.dev.yaml (Ubuntu 26.04 pinned by digest, non-root 1000:1000, Node 24 LTS, npm-latest coding CLI baseline). Setup, the read-only GitHub CLI and agent-context mount contracts, and container commands are documented in AGENTS.md.

Tests use synthetic provider records, a local fixture child, and injected transports. They never invoke Codex, Claude, or Telegram.

npm test
npm run eslint
npm run typecheck
npm run fallow
npm run lint
npm run all-checks

TensorBuzz CI runs these from the repo root; tensorbuzz.yml is the source of truth for the exact CI command sequence (node -v, npm ci, npm run all-checks).

npm run verify:package builds the publishable tarball in a temporary directory, checks its allowlisted contents, and executes threadwire --help from that exact tarball through npm's package runner without using the network.

License

Copyright © 2026 Kasper Stöckel.

Threadwire is licensed under the GNU Affero General Public License v3.0 or later. If you distribute a modified version, or let users interact with a modified version over a network, the AGPL requires you to offer those users the corresponding source code under the same license.