# Use Stashr from the command line

> Search, save, and organize your Stashr library from a terminal, script, or coding agent with the official Stashr CLI.

The Stashr CLI gives people, scripts, and coding agents a small command-line interface to the same library you use on the web. It supports readable terminal output by default and stable JSON for automation.

## Install

Install the CLI globally with your preferred Node package manager:

```sh
npm install --global @stashr/cli
```

Or with Bun:

```sh
bun add --global @stashr/cli
```

The CLI requires Node.js 20 or newer. Confirm the installation with:

```sh
stashr --version
```

## Sign in

Run:

```sh
stashr login
```

The CLI opens Stashr in your browser. Sign in if needed, review the requested permissions, and approve the connection. You return to the same authorization flow after signing in, so you do not need to restart the command.

The CLI stores its refresh token in your operating system's standard application-config directory with private file permissions. It refreshes short-lived access tokens automatically. Run `stashr logout` to revoke the refresh token and remove the local tokens.

## Get help

Run `stashr help` for every command, or ask for help on one command:

```sh
stashr help
stashr help search
stashr search --help
```

Command help includes its options and practical examples. Invalid commands also point back to `stashr help`.

## Search and browse

Search by meaning or browse newest-first:

```sh
stashr search "pricing page inspiration"
stashr list --limit 20
stashr get 019abcde-0000-7000-8000-000000000000
```

Search and list accept repeatable filters:

```sh
stashr search "woodworking" --platform reddit --tag projects
stashr list --state archived --has-note
stashr list --media image --platform instagram --limit 50
```

Available filter groups include tags, platforms, authors, content types, media, favorites, and notes. The corresponding `--*-mode` options choose include/exclude behavior, while `--tag-mode` controls whether repeated tags match any or all values.

Results return one page at a time. If more exist, human output prints a **Next cursor** and JSON includes `nextCursor`. Continue explicitly:

```sh
stashr list --cursor '<nextCursor>'
```

The CLI does not silently fetch every page, which keeps agent output and API usage bounded.

## Save and organize

```sh
stashr save https://example.com/article
stashr update <bookmark-id> --note "Useful pricing breakdown"
stashr update <bookmark-id> --favorite --add-tag research
stashr update <bookmark-id> --remove-tag inbox
stashr update <bookmark-id> --clear-tags
stashr archive <bookmark-id> <another-bookmark-id>
stashr restore <bookmark-id>
```

Saving a URL is idempotent: if it is already in your library, Stashr returns the existing bookmark instead of creating a duplicate.

List tags and manage collections:

```sh
stashr tags
stashr collections list
stashr collections create "Design research"
stashr collections update <collection-id> --name "Product research"
stashr collections delete <collection-id> --confirm
```

Collection deletion removes the collection, not its bookmarks, and always requires `--confirm`. Complex collection rules can be supplied with `--filters-json`; run `stashr help collections` and the subcommand help before scripting them.

## JSON for agents and scripts

Add `--json` to any data command:

```sh
stashr search "design systems" --limit 10 --json
stashr tags --json
```

`search` and `list` keep their original full JSON response for compatibility.
For agent discovery, add `--compact` to return only bounded snippets and useful
metadata instead of full content and platform payloads:

```sh
stashr search "design systems" --compact --json
stashr list --tag research --compact --json
```

Use `stashr get <bookmark-id> --json` only after choosing a result that needs
full text. This discovery-then-fetch pattern keeps context small without hiding
the information needed to choose well.

### Find and inspect images

Rank individual images by their AI vision captions:

```sh
stashr search "warm timber reading nook" --rank image --compact --json
```

Each result includes `matchedMedia.ref`, its bounded caption and alt text, its
dimensions, and a URL when available. A bookmark can appear more than once when
several of its images match. To visually inspect one selected image without
putting image bytes into JSON, download Stashr's bounded preview:

```sh
stashr media <bookmark-id> --ref <media-ref> --output ./preview.jpg --json
```

The command writes a maximum-768px JPEG and returns only file metadata on
stdout. Stored images are available; remote-only images and videos remain
metadata-only.

Successful data is written to stdout. Progress and errors are written to stderr, so piping JSON remains safe. Errors in JSON mode use this shape:

```json
{
  "error": {
    "code": "forbidden",
    "message": "Missing required scope"
  },
  "requestId": "request-123"
}
```

Exit codes are stable by category:

| Code | Meaning |
| --- | --- |
| `0` | Success |
| `1` | General command or HTTP failure |
| `2` | Authentication required or expired |
| `3` | Invalid input |
| `4` | Not found |
| `5` | Permission denied |
| `6` | Network or Stashr server failure |

## Local development and alternate servers

Override the server for one command with `--api-url`, or set it for the shell:

```sh
stashr --api-url http://localhost:3000 login
export STASHR_API_URL=http://localhost:3000
```

OAuth credentials are tied to the server used during login. If you change servers, run `stashr login` again.

## Advanced: headless agents and CI

Most people should use `stashr login`. An unattended runner that cannot open a browser can instead receive a scoped API key through its secret environment:

```sh
export STASHR_API_KEY="stashr_..."
stashr whoami
```

The environment variable takes precedence over a stored OAuth session. The CLI deliberately has no `--api-key` option, so keys do not leak into shell history or process listings.

Create and revoke keys under **Settings → API keys**. Use read access for lookup-only automation, write access for saving and organization, and full access only when collection deletion is required.

## Command reference

| Command | Purpose |
| --- | --- |
| `stashr login` | Sign in with browser OAuth. |
| `stashr logout` | Revoke and remove stored OAuth tokens. |
| `stashr whoami` | Show the authenticated account and plan. |
| `stashr search <query>` | Search bookmarks by meaning and text. |
| `stashr list` | Browse bookmarks newest-first. |
| `stashr get <bookmark-id>` | Read one bookmark in full. |
| `stashr media <bookmark-id> --ref <ref> --output <path>` | Download one bounded image preview. |
| `stashr save <url>` | Save a public URL idempotently. |
| `stashr update <bookmark-id>` | Change note, favorite state, or tags. |
| `stashr archive <bookmark-ids...>` | Reversibly archive bookmarks. |
| `stashr restore <bookmark-ids...>` | Restore archived bookmarks. |
| `stashr tags` | List tags. |
| `stashr collections list` | List collections. |
| `stashr collections create <name>` | Create a collection. |
| `stashr collections update <id>` | Update a collection. |
| `stashr collections delete <id> --confirm` | Delete a collection. |
| `stashr help [command]` | Show general or command-specific help. |

## Troubleshooting

- **Authentication required**: run `stashr login` again.
- **The wrong account is used**: check `stashr whoami`, then run `stashr logout` and `stashr login` again.
- **The browser does not open**: run `stashr login --no-browser` and open the printed URL on the same computer.
- **A command is forbidden**: reconnect so the CLI can request the current permissions.
- **An API call fails unexpectedly**: include the printed request ID when contacting support.

<CardGroup>
  <LinkCard slug="mcp" title="Connect your AI over MCP" description="Give MCP-compatible assistants direct access to Stashr." />
  <LinkCard slug="search" title="Search" description="Learn how Stashr's meaning-based search works." />
</CardGroup>
