Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8a097fc
feat(api): api update
stainless-app[bot] Apr 1, 2026
990b138
feat(api): manual updates
stainless-app[bot] Apr 1, 2026
ec50cae
codegen metadata
stainless-app[bot] Apr 1, 2026
792c2ce
chore(internal): codegen related update
stainless-app[bot] Apr 8, 2026
7d1c53a
feat(api): api update
stainless-app[bot] Apr 1, 2026
2852394
fix: handle empty data set using `--format explore`
stainless-app[bot] Apr 2, 2026
13259ac
fix: use `RawJSON` when iterating items with `--format explore` in th…
stainless-app[bot] Apr 2, 2026
1b23d84
feat: binary-only parameters become CLI flags that take filenames only
stainless-app[bot] Apr 3, 2026
57e1a52
feat: better error message if scheme forgotten in CLI `*_BASE_URL`/`-…
stainless-app[bot] Apr 3, 2026
4fb771a
feat: allow `-` as value representing stdin to binary-only file param…
stainless-app[bot] Apr 3, 2026
6f4709d
chore: switch some CLI Go tests from `os.Chdir` to `t.Chdir`
stainless-app[bot] Apr 3, 2026
132e0f5
chore: mark all CLI-related tests in Go with `t.Parallel()`
stainless-app[bot] Apr 3, 2026
5620db5
feat(api): api update
stainless-app[bot] Apr 3, 2026
de38d20
codegen metadata
stainless-app[bot] Apr 4, 2026
f488623
chore: modify CLI tests to inject stdout so mutating `os.Stdout` isn'…
stainless-app[bot] Apr 4, 2026
ba3a439
codegen metadata
stainless-app[bot] Apr 5, 2026
eb15535
fix: fall back to main branch if linking fails in CI
stainless-app[bot] Apr 7, 2026
6d8d3f4
fix: fix quoting typo
stainless-app[bot] Apr 7, 2026
35c4f7d
feat(api): manual updates
stainless-app[bot] Apr 8, 2026
e70a1d2
feat(api): manual updates
stainless-app[bot] Apr 8, 2026
606036f
feat(api): api update
stainless-app[bot] Apr 8, 2026
89f41fe
feat(api): api update
stainless-app[bot] Apr 8, 2026
628d088
chore: update SDK settings
stainless-app[bot] Apr 8, 2026
11b16d2
release: 0.7.8
stainless-app[bot] Apr 8, 2026
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
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- name: Link staging branch
if: github.repository == 'stainless-sdks/agentmail-cli'
run: |
./scripts/link 'github.com/stainless-sdks/agentmail-go@${{ github.ref_name }}' || true
./scripts/link 'github.com/stainless-sdks/agentmail-go@${{ github.ref_name }}' || go mod edit -dropreplace='github.com/stainless-sdks/agentmail-go'

- name: Bootstrap
run: ./scripts/bootstrap
Expand All @@ -60,7 +60,7 @@ jobs:
- name: Link staging branch
if: github.repository == 'stainless-sdks/agentmail-cli'
run: |
./scripts/link 'github.com/stainless-sdks/agentmail-go@${{ github.ref_name }}' || true
./scripts/link 'github.com/stainless-sdks/agentmail-go@${{ github.ref_name }}' || go mod edit -dropreplace='github.com/stainless-sdks/agentmail-go'

- name: Bootstrap
run: ./scripts/bootstrap
Expand Down Expand Up @@ -107,7 +107,7 @@ jobs:
- name: Link staging branch
if: github.repository == 'stainless-sdks/agentmail-cli'
run: |
./scripts/link 'github.com/stainless-sdks/agentmail-go@${{ github.ref_name }}' || true
./scripts/link 'github.com/stainless-sdks/agentmail-go@${{ github.ref_name }}' || go mod edit -dropreplace='github.com/stainless-sdks/agentmail-go'

- name: Bootstrap
run: ./scripts/bootstrap
Expand Down
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.7.7"
".": "0.7.8"
}
8 changes: 4 additions & 4 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 63
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/agentmail%2Fagentmail-5b7e1869efdc36823facfecf752c92fc0dd69fcaf6c9316da8e58341260bf894.yml
openapi_spec_hash: f0c65e3e3147439fac4573015d4a8a18
config_hash: f6f3698d5c44d64d43573d55bd5d9c49
configured_endpoints: 94
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/agentmail%2Fagentmail-800ca32bd9e05b092bbe726b31890653d74f1d43bb8436a98476b4dc16035e15.yml
openapi_spec_hash: a2cd4922b1e8e7aef452d530efe4658d
config_hash: 1ae33a780b8223537909e04cb1264399
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@
# Changelog

## 0.7.8 (2026-04-08)

Full Changelog: [v0.7.7...v0.7.8](https://github.com/agentmail-to/agentmail-cli/compare/v0.7.7...v0.7.8)

### Features

* allow `-` as value representing stdin to binary-only file parameters in CLIs ([4fb771a](https://github.com/agentmail-to/agentmail-cli/commit/4fb771aa678ef1ecb7d343dae770dbb71e055508))
* **api:** api update ([89f41fe](https://github.com/agentmail-to/agentmail-cli/commit/89f41fe796ce15b93ec8ef05e2a5cf7e3a5a3033))
* **api:** api update ([606036f](https://github.com/agentmail-to/agentmail-cli/commit/606036f0823d4f7866e6f14ed8c1f42e233d8755))
* **api:** api update ([5620db5](https://github.com/agentmail-to/agentmail-cli/commit/5620db56682523df5cc935944c6ebfc59bb79b22))
* **api:** api update ([7d1c53a](https://github.com/agentmail-to/agentmail-cli/commit/7d1c53a967e324aedabd621a2c015d10c7bbd2dc))
* **api:** api update ([8a097fc](https://github.com/agentmail-to/agentmail-cli/commit/8a097fcd316707a55cbc9a6b8afe703b957ba289))
* **api:** manual updates ([e70a1d2](https://github.com/agentmail-to/agentmail-cli/commit/e70a1d2adcc22ed240705c31a29204ccb19c12f9))
* **api:** manual updates ([35c4f7d](https://github.com/agentmail-to/agentmail-cli/commit/35c4f7d6e95015444332830e0c771bd84c5d3099))
* **api:** manual updates ([990b138](https://github.com/agentmail-to/agentmail-cli/commit/990b138aa27685e76755b1d15dfb3848495a0559))
* better error message if scheme forgotten in CLI `*_BASE_URL`/`--base-url` ([57e1a52](https://github.com/agentmail-to/agentmail-cli/commit/57e1a52c1113691d1cbca572aad8596a8f5e41b2))
* binary-only parameters become CLI flags that take filenames only ([1b23d84](https://github.com/agentmail-to/agentmail-cli/commit/1b23d84fd4b71798b92f1911789d7fcaa1c54967))


### Bug Fixes

* fall back to main branch if linking fails in CI ([eb15535](https://github.com/agentmail-to/agentmail-cli/commit/eb15535b59629251822755e30056002d531fe641))
* fix quoting typo ([6d8d3f4](https://github.com/agentmail-to/agentmail-cli/commit/6d8d3f4a18baa6837e93ae0c2972ac917588e2b7))
* handle empty data set using `--format explore` ([2852394](https://github.com/agentmail-to/agentmail-cli/commit/2852394d9c496a915983a2dbc1869cbc9207df88))
* use `RawJSON` when iterating items with `--format explore` in the CLI ([13259ac](https://github.com/agentmail-to/agentmail-cli/commit/13259ac6cd741976f91701e2eb688dc745fa6ea5))
* use RELEASE_PAT to approve and auto-merge release PRs ([dacdd81](https://github.com/agentmail-to/agentmail-cli/commit/dacdd81f4be1104065813f510dda657b516aa844))


### Chores

* **internal:** codegen related update ([792c2ce](https://github.com/agentmail-to/agentmail-cli/commit/792c2ceb7524362f45055e5edbfee07aa3605ef6))
* mark all CLI-related tests in Go with `t.Parallel()` ([132e0f5](https://github.com/agentmail-to/agentmail-cli/commit/132e0f5ff3e6c50c0cad628b2b258f708a3ee2cb))
* modify CLI tests to inject stdout so mutating `os.Stdout` isn't necessary ([f488623](https://github.com/agentmail-to/agentmail-cli/commit/f488623c7a1568221a18d345a3991e130d928720))
* switch some CLI Go tests from `os.Chdir` to `t.Chdir` ([6f4709d](https://github.com/agentmail-to/agentmail-cli/commit/6f4709d39b216adc01607cc55e9c9bfa6f1c0c95))
* update SDK settings ([628d088](https://github.com/agentmail-to/agentmail-cli/commit/628d088add60a690cc24e460ad02fa375b82e651))

## 0.7.7 (2026-03-31)

Full Changelog: [v0.7.6...v0.7.7](https://github.com/agentmail-to/agentmail-cli/compare/v0.7.6...v0.7.7)
Expand Down
62 changes: 55 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,63 @@ agentmail inboxes:threads list --inbox-id inb_xxx

Use `--help` on any command for details.

## Environment variables

| Environment variable | Required |
| -------------------- | -------- |
| `AGENTMAIL_API_KEY` | yes |

## Global flags

| Flag | Description |
| --- | --- |
| `--api-key` | API key (or set `AGENTMAIL_API_KEY`) |
| `--format` | Output format: `json`, `yaml`, `pretty`, `raw`, `explore` |
| `--debug` | Enable debug logging |
| `--help` | Show help |
| `--version` | Show version |
- `--api-key` (can also be set with `AGENTMAIL_API_KEY` env var)
- `--help` - Show command line usage
- `--debug` - Enable debug logging (includes HTTP request/response details)
- `--version`, `-v` - Show the CLI version
- `--base-url` - Use a custom API backend URL
- `--format` - Change the output format (`auto`, `explore`, `json`, `jsonl`, `pretty`, `raw`, `yaml`)
- `--format-error` - Change the output format for errors (`auto`, `explore`, `json`, `jsonl`, `pretty`, `raw`, `yaml`)
- `--transform` - Transform the data output using [GJSON syntax](https://github.com/tidwall/gjson/blob/master/SYNTAX.md)
- `--transform-error` - Transform the error output using [GJSON syntax](https://github.com/tidwall/gjson/blob/master/SYNTAX.md)

### Passing files as arguments

To pass files to your API, you can use the `@myfile.ext` syntax:

```bash
agentmail <command> --arg @abe.jpg
```

Files can also be passed inside JSON or YAML blobs:

```bash
agentmail <command> --arg '{image: "@abe.jpg"}'
# Equivalent:
agentmail <command> <<YAML
arg:
image: "@abe.jpg"
YAML
```

If you need to pass a string literal that begins with an `@` sign, you can
escape the `@` sign to avoid accidentally passing a file.

```bash
agentmail <command> --username '\@abe'
```

#### Explicit encoding

For JSON endpoints, the CLI tool does filetype sniffing to determine whether the
file contents should be sent as a string literal (for plain text files) or as a
base64-encoded string literal (for binary files). If you need to explicitly send
the file as either plain text or base64-encoded data, you can use
`@file://myfile.txt` (for string encoding) or `@data://myfile.dat` (for
base64-encoding). Note that absolute paths will begin with `@file://` or
`@data://`, followed by a third `/` (for example, `@file:///tmp/file.txt`).

```bash
agentmail <command> --arg @data://file.txt
```

## Documentation

Expand Down
7 changes: 7 additions & 0 deletions cmd/agentmail/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ func main() {
prepareForAutocomplete(app)
}

if baseURL, ok := os.LookupEnv("AGENTMAIL_BASE_URL"); ok {
if err := cmd.ValidateBaseURL(baseURL, "AGENTMAIL_BASE_URL"); err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
os.Exit(1)
}
}

if err := app.Run(context.Background(), os.Args); err != nil {
exitCode := 1

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/agentmail-to/agentmail-cli
go 1.25

require (
github.com/agentmail-to/agentmail-go v0.2.0
github.com/agentmail-to/agentmail-go v0.6.0
github.com/charmbracelet/bubbles v0.21.0
github.com/charmbracelet/bubbletea v1.3.6
github.com/charmbracelet/lipgloss v1.1.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
github.com/agentmail-to/agentmail-go v0.2.0 h1:MfFsY6MRMVSuTiT6626Im8vhZz+Khryv6ANcrNA/Izc=
github.com/agentmail-to/agentmail-go v0.2.0/go.mod h1:3NrKbeXLQKRgb9gj2bmCoN9WXDTy9y9yacV070xpvDU=
github.com/agentmail-to/agentmail-go v0.6.0 h1:CCQtBbYE97KASraV2v4IvSuaaJrjKDn97qH1rhMmJt8=
github.com/agentmail-to/agentmail-go v0.6.0/go.mod h1:3NrKbeXLQKRgb9gj2bmCoN9WXDTy9y9yacV070xpvDU=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
Expand Down
4 changes: 4 additions & 0 deletions internal/apiform/form_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,12 @@ var tests = map[string]struct {
}

func TestEncode(t *testing.T) {
t.Parallel()

for name, test := range tests {
t.Run(name, func(t *testing.T) {
t.Parallel()

buf := bytes.NewBuffer(nil)
writer := multipart.NewWriter(buf)
writer.SetBoundary("xxx")
Expand Down
4 changes: 4 additions & 0 deletions internal/apiquery/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
)

func TestEncode(t *testing.T) {
t.Parallel()

tests := map[string]struct {
val any
settings QuerySettings
Expand Down Expand Up @@ -114,6 +116,8 @@ func TestEncode(t *testing.T) {

for name, test := range tests {
t.Run(name, func(t *testing.T) {
t.Parallel()

query := map[string]any{"query": test.val}
values, err := MarshalWithSettings(query, test.settings)
if err != nil {
Expand Down
40 changes: 40 additions & 0 deletions internal/autocomplete/autocomplete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
)

func TestGetCompletions_EmptyArgs(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{Name: "generate", Usage: "Generate SDK"},
Expand All @@ -26,6 +28,8 @@ func TestGetCompletions_EmptyArgs(t *testing.T) {
}

func TestGetCompletions_SubcommandPrefix(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{Name: "generate", Usage: "Generate SDK"},
Expand All @@ -43,6 +47,8 @@ func TestGetCompletions_SubcommandPrefix(t *testing.T) {
}

func TestGetCompletions_HiddenCommand(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{Name: "visible", Usage: "Visible command"},
Expand All @@ -57,6 +63,8 @@ func TestGetCompletions_HiddenCommand(t *testing.T) {
}

func TestGetCompletions_NestedSubcommand(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{
Expand All @@ -79,6 +87,8 @@ func TestGetCompletions_NestedSubcommand(t *testing.T) {
}

func TestGetCompletions_FlagCompletion(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{
Expand All @@ -102,6 +112,8 @@ func TestGetCompletions_FlagCompletion(t *testing.T) {
}

func TestGetCompletions_ShortFlagCompletion(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{
Expand All @@ -123,6 +135,8 @@ func TestGetCompletions_ShortFlagCompletion(t *testing.T) {
}

func TestGetCompletions_FileFlagBehavior(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{
Expand All @@ -142,6 +156,8 @@ func TestGetCompletions_FileFlagBehavior(t *testing.T) {
}

func TestGetCompletions_NonBoolFlagValue(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{
Expand All @@ -161,6 +177,8 @@ func TestGetCompletions_NonBoolFlagValue(t *testing.T) {
}

func TestGetCompletions_BoolFlagDoesNotBlockCompletion(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{
Expand All @@ -185,6 +203,8 @@ func TestGetCompletions_BoolFlagDoesNotBlockCompletion(t *testing.T) {
}

func TestGetCompletions_ColonCommands_NoColonTyped(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{Name: "config:get", Usage: "Get config value"},
Expand All @@ -202,6 +222,8 @@ func TestGetCompletions_ColonCommands_NoColonTyped(t *testing.T) {
}

func TestGetCompletions_ColonCommands_ColonTyped_Bash(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{Name: "config:get", Usage: "Get config value"},
Expand All @@ -221,6 +243,8 @@ func TestGetCompletions_ColonCommands_ColonTyped_Bash(t *testing.T) {
}

func TestGetCompletions_ColonCommands_ColonTyped_Zsh(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{Name: "config:get", Usage: "Get config value"},
Expand All @@ -240,6 +264,8 @@ func TestGetCompletions_ColonCommands_ColonTyped_Zsh(t *testing.T) {
}

func TestGetCompletions_BashStyleColonCompletion(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{Name: "config:get", Usage: "Get config value"},
Expand All @@ -257,6 +283,8 @@ func TestGetCompletions_BashStyleColonCompletion(t *testing.T) {
}

func TestGetCompletions_BashStyleColonCompletion_NoMatch(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{Name: "config:get", Usage: "Get config value"},
Expand All @@ -271,6 +299,8 @@ func TestGetCompletions_BashStyleColonCompletion_NoMatch(t *testing.T) {
}

func TestGetCompletions_ZshStyleColonCompletion(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{Name: "config:get", Usage: "Get config value"},
Expand All @@ -287,6 +317,8 @@ func TestGetCompletions_ZshStyleColonCompletion(t *testing.T) {
}

func TestGetCompletions_MixedColonAndRegularCommands(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{Name: "generate", Usage: "Generate SDK"},
Expand All @@ -305,6 +337,8 @@ func TestGetCompletions_MixedColonAndRegularCommands(t *testing.T) {
}

func TestGetCompletions_FlagWithBoolFlagSkipsValue(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{
Expand All @@ -329,6 +363,8 @@ func TestGetCompletions_FlagWithBoolFlagSkipsValue(t *testing.T) {
}

func TestGetCompletions_MultipleFlagsBeforeSubcommand(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{
Expand All @@ -353,6 +389,8 @@ func TestGetCompletions_MultipleFlagsBeforeSubcommand(t *testing.T) {
}

func TestGetCompletions_CommandAliases(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{Name: "generate", Aliases: []string{"gen", "g"}, Usage: "Generate SDK"},
Expand All @@ -372,6 +410,8 @@ func TestGetCompletions_CommandAliases(t *testing.T) {
}

func TestGetCompletions_AllFlagsWhenNoPrefix(t *testing.T) {
t.Parallel()

root := &cli.Command{
Commands: []*cli.Command{
{
Expand Down
Loading
Loading