Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 21 additions & 23 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@

## Repo

- Standalone TypeScript package for the put.io CLI, `@putdotio/cli` with the `putio` binary; people and agents use it from npm, Homebrew, and standalone binaries
- Main code lives in `src/*`; layer rules in [Architecture](docs/architecture.md)
- Durable docs live in `docs/*`; release wiring in [Distribution](docs/distribution.md)
- Consumer-facing skills live in `skills/*`
- Contributor setup and validation in [Contributing](CONTRIBUTING.md)
- `@putdotio/cli`, the `putio` binary, shipped through npm, Homebrew, and standalone binaries.
- Code lives in `src/*`; layer rules are in [Architecture](docs/architecture.md).
- `skills/putio-cli` is the consumer skill that ships in the npm package.
- Contributor setup is in [Contributing](CONTRIBUTING.md).

## Commands

- `pnpm exec vp run verify`: the gate; pre-push and CI run it
- Focused checks are the `scripts` in [package.json](package.json); run them as `pnpm exec vp run <script>`
- `smoke:pack` writes its report to `.artifacts/smoke-packed-install.json`
- `pnpm exec vp run verify`: the gate; pre-push and CI run it.
- Focused checks are the `scripts` in [package.json](package.json); run them as `pnpm exec vp run <script>`.
- `smoke:pack` writes its report to `.artifacts/smoke-packed-install.json`.

## Worktrees

Expand All @@ -21,19 +20,16 @@ Run `pnpm exec vp install`, `pnpm exec vp config`, then

## Development Guidance

- Keep `README.md` user-facing. Put contributor workflow in `CONTRIBUTING.md`, architecture in `docs/*`, and consumer usage patterns in `skills/*`.
- Keep command modules thin and move shared behavior into internal Effect-native helpers and services.
- Prefer `Effect`, services, layers, `Schema`, and tagged errors over ad hoc control flow.
- Treat JSON output as the machine contract and terminal output as a separate adapter layer.
- Update docs when flags, command behavior, or architecture boundaries change.
- When the public CLI surface or agent-facing setup flow changes, update [`README.md`](README.md) and [`skills/putio-cli/SKILL.md`](skills/putio-cli/SKILL.md) together so the copy-paste prompt and consumer guidance stay aligned.
- Keep docs free of volatile metrics.
- `README.md` is for users, `CONTRIBUTING.md` for contributors, `docs/*` for architecture, `skills/*` for consumer usage.
- Keep command modules thin; shared behavior goes in Effect services and layers with `Schema` boundaries and tagged errors.
- JSON output is the machine contract; terminal output is a separate adapter.
- When commands, flags, output, auth, `automation`, or `describe.version` change in a way consumers need, update [`README.md`](README.md), [`skills/putio-cli/SKILL.md`](skills/putio-cli/SKILL.md), and its references in the same change.

## Effect

This repository uses the Effect TypeScript library. The installed version's own
guide is `node_modules/effect/AGENTS.md`; consult it for the APIs the change
touches, and search `node_modules/effect/src` for anything it does not cover.
The installed version's guide is `node_modules/effect/AGENTS.md`; consult it for
the APIs the change touches, and search `node_modules/effect/src` for anything it
does not cover.

## Proof

Expand All @@ -48,11 +44,13 @@ touches, and search `node_modules/effect/src` for anything it does not cover.

## Delivery

Pull requests squash-merge to `main`. A push to `main` runs `verify`; when the commits since the last release include `feat`, `fix`, `perf`, a revert, or a breaking change, semantic-release publishes `@putdotio/cli` to npm, attaches the standalone binaries to the GitHub Release, and updates the `putdotio/homebrew-tap` formula. `docs`, `chore`, `test`, and `ci` release nothing. `install.sh` on `main` is the live installer that `curl | sh` users fetch, so a merge changes it at once. Partial-release recovery: [Distribution](docs/distribution.md#recover).
- Pull requests squash-merge to `main`; every merge must be releasable.
- The squash commit's type decides the release ([`.releaserc.json`](.releaserc.json)); a release ships npm, binaries, and the Homebrew formula at once ([`ci.yml`](.github/workflows/ci.yml)).
- [`install.sh`](install.sh) on `main` is the live `curl | sh` installer; a merge changes it at once.
- Partial release: dispatch `CI` from `main` with the existing tag as `release_tag` ([`ci.yml`](.github/workflows/ci.yml)). Use [`Backfill Release Assets`](.github/workflows/backfill-release-assets.yml) only for releases published before draft-first releases.

## Skills

- `skills/*` is for reusable consumer-facing skills, not repo onboarding.
- `skills/putio-cli/SKILL.md` is the router; surface-specific detail lives in the matching reference file.
- `skills/putio-cli/agents/openai.yaml` is the Codex picker display and default-prompt metadata; keep it aligned with the skill frontmatter.
- Refresh the skill and its references in the same change whenever `describe.version`, commands, output, auth, or `automation` change in a way consumers need to know.
- `skills/*` holds consumer skills, not repo onboarding.
- `skills/putio-cli/SKILL.md` routes; surface detail lives in the matching reference file.
- `skills/putio-cli/agents/openai.yaml` is the Codex picker metadata; keep it aligned with the skill frontmatter.
47 changes: 22 additions & 25 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,55 @@

## Setup

Use the Node version required by [`package.json`](./package.json), then install dependencies:
Use the Node version in [`.node-version`](./.node-version), then install
dependencies and the tracked Git hooks. Pre-push runs the same `verify` gate as
CI.

```bash
pnpm exec vp install
```

Install the tracked pre-commit and pre-push hooks; pre-push runs the same `verify` gate as CI:

```bash
pnpm exec vp config
```

## Run Locally

Start the local build watcher:
Watch and rebuild:

```bash
pnpm exec vp run dev
```

Build the CLI once and try the shipped entrypoint:
Build once and run the shipped entrypoint:

```bash
pnpm exec vp run build
./dist/bin.mjs describe
```

## Validation
## Checks

Run the main repository gate before opening or updating a pull request:
Run the gate before opening or updating a pull request:

```bash
pnpm exec vp run verify
```

Run tests through the repo-local Vite+ binary (`pnpm exec vp test`) so the
runner and `vite-plus/test` imports share one Vitest runtime.

Focused checks are listed under [Commands in AGENTS.md](AGENTS.md#commands).

## Release Publishing
Run tests through `pnpm exec vp test` so the runner and `vite-plus/test` imports
share one Vitest runtime. Focused checks and which one proves which change are
in [AGENTS.md](AGENTS.md#proof).

See [Distribution](docs/distribution.md) for release automation, credentials, and binary asset publishing.
## Effect Versions

## Development Notes
Pin `effect` to the version the pinned put.io SDK depends on; `smoke:pack` fails
if the packed install resolves more than one. The build bundles the SDK, so the
CLI and SDK share one Effect runtime. If an SDK release needs an Effect API the
pinned runtime lacks, add a pnpm patch and register it in
[`pnpm-workspace.yaml`](./pnpm-workspace.yaml).

- `verify` is the delivery gate. It enforces the production Effect runtime boundary and dead-code checks, exercises the packed CLI through success and failure paths, and writes the smoke report to `.artifacts/smoke-packed-install.json`.
- Keep the exact Effect versions aligned with the `effect` version the pinned put.io SDK depends on; `smoke:pack` fails if the packed install resolves more than one. The build bundles the SDK so installed CLIs and the SDK share one Effect runtime; if an SDK release depends on an Effect API the pinned runtime lacks, add a pnpm patch under `patches/` and register it in `pnpm-workspace.yaml`.
- Doc placement rules: [Development Guidance in AGENTS.md](AGENTS.md#development-guidance).
## Release Setup

## Pull Requests
Maintainers keep these provider settings in sync with
[`ci.yml`](.github/workflows/ci.yml); the release fails without them.

- Keep changes focused and explicit.
- Add or update tests when behavior changes.
- Prefer small follow-up pull requests over mixing unrelated cleanup into one branch.
- GitHub Environment `release`: holds the credentials `ci.yml` reads, no approval, `main` only.
- `putio-ci` GitHub App: Contents read and write on `putio-cli` and `putdotio/homebrew-tap`.
- npm Trusted Publishing for `@putdotio/cli`: owner `putdotio`, repository `putio-cli`, workflow `ci.yml`, environment `release`.
139 changes: 34 additions & 105 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ brew install putio-cli
curl -fsSL https://raw.githubusercontent.com/putdotio/putio-cli/main/install.sh | sh
```

Installs the latest release to `~/.local/bin/putio`

Custom dir:
Installs the latest release to `~/.local/bin/putio`. Pick another directory:

```bash
curl -fsSL https://raw.githubusercontent.com/putdotio/putio-cli/main/install.sh | INSTALL_DIR=/usr/local/bin sh
Expand All @@ -54,9 +52,7 @@ putio version

## Quick Start

### For Agents

Copy-paste prompt:
Copy-paste prompt for agents:

```text
Use `putio` to interact with put.io from the terminal.
Expand All @@ -67,8 +63,6 @@ https://github.com/putdotio/putio-cli
Read and follow this usage skill before operating the CLI:
https://raw.githubusercontent.com/putdotio/putio-cli/main/skills/putio-cli/SKILL.md

When only one workflow is relevant, follow the linked reference docs from that skill instead of loading unrelated guidance.

If `putio` is not installed, follow the install instructions in the repository README:
https://github.com/putdotio/putio-cli/blob/main/README.md

Expand Down Expand Up @@ -99,148 +93,83 @@ Inspect the live contract:
putio describe --output json
```

Link your account:
Link your account; agents and test harnesses use a named profile:

```bash
putio auth login
```

Create or refresh a named agent/test profile:

```bash
putio auth login --profile automation
putio auth profiles use automation
```

The CLI does not accept put.io account credentials. Its login flow delegates authorization to the
configured web app (`app.put.io` by default) and stores only the returned OAuth token.

Use `auth login --timeout-seconds 30` to bound the authorization wait, including
pending polls and polling delays. A timeout leaves saved auth state unchanged.
Login hands approval to the put.io web app (`app.put.io` by default) and stores
only the returned OAuth token; the CLI never takes account credentials.
`--timeout-seconds` bounds the wait; a timeout leaves saved auth unchanged.

Check the auth source:
Check auth without exposing the token:

```bash
putio whoami --fields auth --output json
```

Check a named profile without exposing token material:

```bash
putio auth status --profile automation --output json
```

List and remove named profiles:

```bash
putio auth profiles list --output json
putio auth profiles remove automation
```

Approve a code displayed by another device:

```bash
putio auth approve PUTIO1 --dry-run --output json
putio auth approve PUTIO1 --output json
```

Read a small JSON result:
Read, stream, and write:

```bash
putio files list --per-page 5 --fields files,total --output json
```

Upload a local file:

```bash
putio transfers list --page-all --output ndjson
putio files upload --path ./movie.mp4 --parent-id 42 --dry-run --output json
putio files upload --path ./movie.mp4 --parent-id 42 --output json
```

Read or update a saved watch position:

```bash
putio files start-from get 42 --output json
putio files start-from set 42 95 --dry-run --output json
putio files start-from reset 42 --dry-run --output json
```

Inspect the HLS master playlist put.io serves for a video. The default is the MP4 conversion when one exists; `--original` asks for the original file:

```bash
putio files hls-manifest 42 --output json
putio files hls-manifest 42 --original --fields manifest --output json
putio files hls-manifest 42 --max-subtitle-count 1 --subtitle-language en --output text
```

Stream larger reads:

```bash
putio transfers list --page-all --output ndjson
```

Call a JSON-compatible TypeScript SDK operation that does not have a dedicated command:
Call an SDK operation that has no dedicated command. `sdk call` treats every
operation as mutating and needs exactly one of `--dry-run` or `--execute`:

```bash
putio sdk list --output json
putio sdk call --operation files.get --args '[42]' --dry-run --output json
putio sdk call --json '{"operation":"files.get","args":[42]}' --execute --output json
```

`sdk call` treats every operation as potentially mutating. It requires exactly one of `--dry-run`
or `--execute`, resolves auth through the normal profile selection, and only traverses own SDK
properties. `sdk list` marks as unsupported the operations that require runtime objects or binary
output, and those whose positional or scalar credentials cannot be safely redacted. Supported keyed
credential fields and token-bearing URLs are redacted in plans and results.
Structured failures exit with status 1 and write JSON to stderr. Read
[error handling](skills/putio-cli/references/guardrails.md) before matching on
status codes. The [skill references](skills/putio-cli/SKILL.md) cover the other
commands.

Structured failures exit with status 1 and write JSON to stderr. SDK errors can include
`error.httpStatusCode`, `error.statusCode` (SDK-normalized), and `error.errorType`.
`describe.automation.structuredErrorMetadata` reports support. Raw bodies, requests,
and causes are omitted. See [error handling](skills/putio-cli/references/guardrails.md)
for status interpretation and missing-file checks.
## Environment

## Tips
- `PUTIO_CLI_TOKEN`: headless auth; overrides persisted auth and profiles.
- `PUTIO_CLI_PROFILE`: selects a persisted profile.
- `PUTIO_CLI_CONFIG_PATH`: moves the config file, for example to isolate test state.
- `PUTIO_CLI_API_BASE_URL`: another API. `files upload` then also needs
`PUTIO_CLI_UPLOAD_BASE_URL`; without it, uploads refuse rather than send that
token to upload.put.io.

- Use `--output json` when you want a stable machine-readable contract for scripts, agents, and automation.
- Use `--output ndjson` for large or continuous read workflows. Page production waits for stdout writes, so slow pipe readers apply backpressure.
- Use `--fields` to keep structured responses small.
- Use `--dry-run` before mutating commands.
- Set `PUTIO_CLI_TOKEN` for headless auth; it overrides persisted auth and selected profiles.
- Set `PUTIO_CLI_PROFILE` to select a persisted profile for automation.
- Use `PUTIO_CLI_CONFIG_PATH` to override the default config location and isolate test state.
- Pointing `PUTIO_CLI_API_BASE_URL` at another API also needs `PUTIO_CLI_UPLOAD_BASE_URL` for `files upload`; without it, uploads refuse rather than send that token to upload.put.io.
- If no profile is specified, the configured default profile is used when present; otherwise legacy single-token config remains supported.
`--output ndjson` waits for each stdout write before fetching the next page, so
a slow reader applies backpressure.

## Crash Reporting and Diagnostics
## Crash Reporting

Official releases send privacy-safe crash reports for unexpected CLI failures by default. There is
no usage analytics. Manage the persisted preference with:
Official releases send privacy-safe crash reports for unexpected failures by
default. There is no usage analytics. The preference persists in the CLI config
for every run, CI and agents included; `DO_NOT_TRACK` does not override it.

```bash
putio telemetry disable
putio telemetry status
putio telemetry enable
```

The preference lives in the private CLI config and applies to interactive, CI, and agent runs alike;
`DO_NOT_TRACK` does not override it. Missing config keeps reporting enabled; unreadable or invalid
config disables it for that process. The `crashReporting` object in `describe` shows the effective
state, flush deadline, and captured-field allowlist.

A process sends at most one synthetic event: a random ID, timestamp, one of three fixed failure
categories, fixed runtime labels, and the package release. It never contains the original error,
credentials, config, command arguments, request data, paths, or identifiers.
[Architecture](./docs/architecture.md#crash-reporting-policy) has the full policy. Use the private
contact in the [put.io security policy](https://github.com/putdotio/.github/blob/main/SECURITY.md)
for sensitive reports or deletion requests.
A report holds a random ID, timestamp, failure category, runtime labels, and the
release. It never holds the error, credentials, config, arguments, request data,
paths, or identifiers. The [crash-reporting policy](./docs/architecture.md#crash-reporting-policy)
has the details. Send deletion requests to the private contact in the
[put.io security policy](https://github.com/putdotio/.github/blob/main/SECURITY.md).

## Docs

- [Architecture](./docs/architecture.md)
- [Distribution](./docs/distribution.md)
- [Contributing](./CONTRIBUTING.md)
- [Security](https://github.com/putdotio/.github/blob/main/SECURITY.md)

## License

This project is available under the MIT license. See [LICENSE](./LICENSE).
MIT. See [LICENSE](./LICENSE).
Loading