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

@tama-computer/sdk

v0.1.2

Published

Agent-friendly TypeScript SDK for Tama

Readme

Tama TypeScript SDK

Typed, promise-based, agent-friendly access to Tama machines from Node.js and browser applications. The SDK mirrors the Tama CLI while keeping actions scoped to TypeScript objects.

Install

Node.js 20 or newer is required for the Node entry point.

npm install @tama-computer/[email protected]

Authenticate

The simplest local setup is to install the Tama CLI, run tama login, and let the Node SDK reuse the selected CLI profile:

curl -fsSL https://tama.computer/install | sh
tama login
import { Tama } from '@tama-computer/sdk'

const tama = new Tama()
console.log((await tama.identity()).account?.id)

In CI, set TAMA_TOKEN instead. Set TAMA_API_URL only when using a non-default gateway.

export TAMA_TOKEN="..."
export TAMA_API_URL="https://gateway.tama.computer" # optional

You can also pass a token explicitly:

const tama = new Tama({ apiKey: process.env.TAMA_TOKEN! })

Configuration precedence is explicit constructor values, TAMA_* environment variables, then the selected CLI profile. TAMA_PROFILE selects a named CLI profile. The SDK uses TAMA_API_URL; the CLI's endpoint override is named TAMA_API.

Browser applications use the browser-safe entry point and provide their current access token. A token provider is called for every request, so rotating dashboard tokens stay fresh.

import { Tama } from '@tama-computer/sdk/browser'

const tama = new Tama({
  apiUrl: 'https://gateway.tama.computer',
  apiKey: async () => await auth.currentAccessToken(),
})

Safe end-to-end example

This creates a machine, runs a command and a Codex session, and always stops the machine so billing pauses. stop() snapshots the machine and is reversible; delete()/rm() destroys it.

import { Tama } from '@tama-computer/sdk'

const tama = new Tama()
const machine = await tama.new({ name: 'typescript-sdk-example' })
try {
  const result = await machine.exec(['python', '--version'], { check: true })
  process.stdout.write(result.stdout)

  const prompt = await machine.prompt(
    'Inspect /workspace and write a concise README for the project.',
    { agent: 'codex', check: true },
  )
  process.stdout.write(prompt.output)
} finally {
  await machine.stop()
}

The client owns no background process that needs closing. Letting the local object go out of scope does not stop remote machines. Keep the try/finally cleanup when code creates or starts billable resources.

Machines

The common workflows mirror the CLI: new, list, get, rm, stop, start, fork, exec, logs, prompt, expose, unexpose, ports, desktop, terminal, and enableSsh.

for (const machine of await tama.list({ all: true })) {
  console.log(machine.id, machine.name, machine.status)
}

const machine = await tama.get('worker')
await machine.stop()

if (machine.snapshot) {
  console.log(machine.snapshot.diskSnapshotId)
  console.log('warm checkpoint:', machine.snapshot.hasMemory)
}

await machine.start()

new() and start() wait for the machine to become ready by default. Pass wait: false for detached provisioning. exec(..., { check: true }) and prompt(..., { check: true }) raise CommandError when the remote process exits non-zero. A detached prompt has no exit code to check yet, so combining detach: true with check: true is rejected. Long commands have no artificial RPC deadline; pass exec(..., { timeoutMs: 300_000 }) when the caller needs a five-minute bound.

Idle auto-stop

Auto-stop is disabled by default. Set autoStopSeconds: 900 when creating a machine to snapshot and stop it after 15 minutes without Tama-visible activity. The minimum enabled value is 60 seconds; 0 disables the policy.

const machine = await tama.new({ name: 'worker', autoStopSeconds: 15 * 60 })
console.log(machine.lastActiveAt, machine.autoStopAt)
await machine.keepActive() // explicit heartbeat for an external/direct workflow

CLI/SDK commands, SSH/tunnels, agent sessions, and traffic through published HTTP or WebSocket ports refresh the deadline automatically. A process doing background compute with no Tama-visible traffic can look idle; disable auto-stop for that workload, or call keepActive() from its controller.

Complete public surface

Prefer object methods for one machine and collections for secondary resources:

await tama.identity()                          // account/workspace identity
await tama.usage(30)                          // credit balance and metered usage
await tama.offers()                           // available machine shapes
await tama.new({ ... })                       // create a machine
await tama.list({ all: true })                // include stopped machines
await tama.get('worker')                      // get by name or id
await tama.keepActive('worker')               // explicit idle-policy heartbeat
await tama.rm('worker')                       // permanently delete
await tama.stop('worker')                     // snapshot and stop
await tama.start('worker')                    // start and wait until ready
await tama.fork(snapshotId, { name: 'copy' }) // fork an immutable snapshot
await tama.exec('worker', ['pytest', '-q'], { check: true })
await tama.prompt('worker', 'Fix the tests', { agent: 'codex', check: true })
tama.logs(sessionId)                          // durable session transcript
tama.logs(machineId, pid)                     // low-level process log stream
await tama.expose('worker', 8000)             // publish a port; returns its URL
await tama.unexpose('worker', 8000)
await tama.ports('worker')                    // Map<port, public URL | undefined>
await tama.desktop('worker')                  // browser desktop URL
await tama.terminal('worker')                 // browser terminal URL
await tama.enableSsh('worker', publicKey)

The same machine-scoped actions are available on Machine: refresh, keepActive, exec, prompt, stop, start, delete, expose, unexpose, desktop, terminal, and enableSsh. Its most useful properties are id, name, status, statusDetail, autoStopSeconds, lastActiveAt, autoStopAt, data, and the restore point returned by a stop in snapshot.

Every secondary collection is explicit:

await tama.machines.create({ ... }) // also get/list/delete/stop/start
await tama.snapshots.create('worker', { label: 'baseline' })
await tama.snapshots.list({ machine: 'worker', automatic: false })
await tama.snapshots.fork(snapshotId, { name: 'experiment' })
await tama.templates.create('worker', { name: 'base', description: '...', public: false })
await tama.templates.list()
await tama.templates.delete(templateId)
await tama.secrets.set('OPENAI_API_KEY', value) // values are never returned
await tama.secrets.list()
await tama.secrets.delete('OPENAI_API_KEY')
const created = await tama.tokens.create('ci') // created.secret is shown once
await tama.tokens.list()
await tama.tokens.revoke(created.id)
await tama.sessions.list('worker')
tama.sessions.logs(sessionId)
await tama.files.list('worker', '/workspace')

startCreditPurchase(amountCents) returns a Stripe checkout URL and confirmCreditPurchase(sessionId) refreshes the balance after the browser returns. Send a human to the console rather than automating a payment flow. tama.raw exposes the generated Connect client for forward compatibility; normal code should use the typed helpers above.

Detached agent session

const machine = await tama.get('worker')
const session = await machine.prompt(
  'Run the test suite, fix failures, and summarize the patch.',
  { agent: 'codex', detach: true },
)

console.log('session:', session.id)
for await (const event of tama.logs(session.id)) process.stdout.write(event.data)

Exiting the local process does not stop a detached agent session. Its transcript is durable and can be followed later with tama.logs(session.id).

Snapshots, forks, templates, secrets, and tokens

const snapshot = await tama.snapshots.create('worker', { label: 'baseline' })
if (snapshot) {
  const fork = await tama.snapshots.fork(snapshot.id, { name: 'experiment-1' })
  await fork.stop()
}

await tama.snapshots.list({ machine: 'worker' })
await tama.templates.list()
await tama.secrets.set('OPENAI_API_KEY', '...')
await tama.tokens.create('ci')

Snapshots and templates pin the machine's complete root filesystem as one immutable disk snapshot. A normal stop may also seal a memory checkpoint against that disk state, allowing a warm resume. Secret values are never returned by the SDK.

Errors and retries

Catch TamaError for the complete error family, or a specific subclass such as AuthenticationError, NotFoundError, ValidationError, or CommandError.

Read-only RPCs retry short UNAVAILABLE and DEADLINE_EXCEEDED failures with bounded exponential backoff. Mutations are never retried automatically: a timed-out create, exec, or snapshot may already be running server-side. After an ambiguous mutation failure, inspect state with list({ all: true }) or get() before trying it again.

The timeoutMs on new Tama(...) bounds ordinary control-plane RPCs. Operations that legitimately seal or move machine state—stop, snapshot, template capture, delete, and exec—do not inherit that short deadline. exec(..., { timeoutMs: ... }) is the explicit opt-in bound for a remote command.

The generated protobuf schema is available as proto, and the raw generated service client is available as tama.raw when a new RPC lands before a convenience wrapper.

Full documentation: https://tama.computer/docs/#typescript-sdk

Development

From sdks/typescript in the Tama repository:

npm install
npm run generate
npm run typecheck
npm test
npm run lint
npm run build

Generated protobuf code is committed, so installing the package does not require Buf or protoc.