Skip to content

jingu/ladle

Repository files navigation

  ██
  ██
  ██       _     ____   _      _____
  ██      / \   |  _ \ | |    | ____|
  ██     / _ \  | | | || |    |  _|
  ██    / ___ \ | |_| || |___ | |___
 ▄██▄  /_/   \_\|____/ |_____||_____|
██████
 ▀████▀

日本語

Edit S3, Google Cloud Storage, and Azure Blob Storage files directly from your terminal. One command.

ladle s3://mybucket/config.json
ladle gs://mybucket/config.json
ladle az://mycontainer/config.json

Download, edit in your favorite editor, diff, confirm, upload — all in one shot. No manual download/upload, no web console, no scripts.

Why ladle?

  • One command to editladle s3://bucket/file opens, edits, diffs, and uploads
  • Metadata tooladle --meta s3://bucket/file edits ContentType, CacheControl, etc. as YAML
  • Any terminal editor — vim, emacs, nano — set EDITOR or --editor
  • Safe by default — colored diff + confirmation before every upload
  • Pipe & redirect — works in shell pipelines and scripts with auto-detection
  • Browse & filter — interactive TUI browser with vim-style / search

Quick Examples

Edit a file

$ ladle s3://myapp/config.json
Downloading s3://myapp/config.json ...
Temp file: /tmp/ladle-123/config.json

  (your editor opens, you make changes, save and close)

File: s3://myapp/config.json

--- original
+++ modified
@@ -1,3 +1,3 @@
 {
-  "debug": false,
+  "debug": true,
   "port": 8080
 }

Upload changes? [y/N]: y
Uploading to s3://myapp/config.json ...
Done.

Edit metadata

$ ladle --meta s3://myapp/index.html
Fetching metadata for s3://myapp/index.html ...

  (editor opens with YAML)

# s3://myapp/index.html
ContentType: text/html
CacheControl: max-age=3600
Metadata:
  author: alice

  (change CacheControl, save and close)

--- original
+++ modified
@@ -2,3 +2,3 @@
 ContentType: text/html
-CacheControl: max-age=3600
+CacheControl: max-age=86400
 Metadata:

Update metadata? [y/N]: y
Done.

Metadata updates use the S3 CopyObject API — no re-upload of file content.

Pipe & Redirect

ladle detects shell redirection so you can use it in pipelines and scripts — no interactive editor needed.

# Download to local file
ladle s3://myapp/config.json > config.json

# Upload from local file (shows diff, asks confirmation)
ladle s3://myapp/config.json < config.json

# Skip confirmation
ladle --yes s3://myapp/config.json < config.json

# Preview changes without uploading
ladle --dry-run s3://myapp/config.json < config.json

# Export / import metadata as YAML
ladle --meta s3://myapp/index.html > meta.yaml
ladle --meta s3://myapp/index.html < meta.yaml

# Transform and re-upload
ladle s3://myapp/config.json | jq '.debug = true' | ladle --yes s3://myapp/config.json

# List objects/buckets (one URI per line; directories keep trailing /).
# Redirect or pipe so stdout is non-TTY — a bare terminal opens the TUI browser instead.
ladle s3://myapp/config/ > objects.txt   # objects + subdirectories under config/
ladle s3:// | grep myapp                  # all buckets, as s3://<bucket>/

# List an object's versions (tab-separated: id, modified, size, latest, delete-marker)
ladle --versions s3://myapp/config.json > versions.tsv

When stdout is redirected, a directory URI (or bare scheme) prints a listing and --versions prints version history, instead of opening the interactive TUI.

When stdin is redirected, confirmation reads from /dev/tty. Use --yes to skip in non-interactive environments. If the object doesn't exist yet, stdin upload creates it as a new object.

Browse files

$ ladle s3://myapp/

      ██  _   ___  _    ____
     ██  /_\ | _ \| |  | __|
  ▄▄██▄ / _ \| | || |__| _|
  ██████_/ \_\___/|____|____|
   ▀██▀  v1.0.0

  s3://myapp

> 📁 config/
  📁 static/
  📝 index.html              2.1 KB  2026-02-19 02:08
  📝 readme.md               1.3 KB  2026-02-19 02:08
  ..

  / index▏
  ↑/↓ navigate  ←/→ collapse/expand  enter select  - up  / filter  esc×2 quit
  • ↑/↓ navigate, ←/→ expand/collapse directories
  • / to filter — incremental search across expanded tree
  • Enter to edit a file, then return to the browser
  • on a file to open the context menu
  • - to go up a directory

Context menu

Press on a file to open the context menu:

  s3://myapp

  📁 config/
  📁 static/
> 📝 index.html              2.1 KB  2026-02-19 02:08
  📝 readme.md               1.3 KB  2026-02-19 02:08
  ..

  ╭──────────────────╮
  │ index.html       │
  │ > Edit           │
  │   Edit metadata  │
  │   Download to... │
  │   Copy to...     │
  │   Move to...     │
  │   Versions       │
  │   Delete         │
  ╰──────────────────╯

  ↑/↓ navigate  enter select  esc/← close
Action Description
Edit Open the file in your editor
Edit metadata Edit ContentType, CacheControl, etc. as YAML
Download to... Download to a local directory (tab completion supported)
Copy to... Copy to another key in the same bucket
Move to... Move to another key in the same bucket
Versions View version history and restore a previous version (S3 / GCS / Azure Blob versioning)
Delete Delete the object (with confirmation)

Version history

View and restore previous versions of objects (requires versioning enabled — S3 bucket versioning, GCS object versioning, or Azure Blob versioning).

# Open version history directly
ladle --versions s3://myapp/config.json
      ██  _   ___  _    ____
     ██  /_\ | _ \| |  | __|
  ▄▄██▄ / _ \| | || |__| _|
  ██████_/ \_\___/|____|____|
   ▀██▀  v1.0.0

  s3://myapp

  ╭──────────────────────────────────────╮  ╭──────────────────────────────────╮
  │ Versions: config.json                │  │ Preview                          │
  │ > aB3dE6fG7h1i  2026-02-27 10:30    │  │ {                                │
  │       812 B  (current)               │  │   "debug": true,                 │
  │   kL9mN0pQ2r3s  2026-02-26 14:15    │  │   "port": 8080,                  │
  │       795 B                          │  │   "host": "0.0.0.0"              │
  │   tU4vW5xY6z7a  2026-02-25 09:00    │  │ }                                │
  │       780 B                          │  │                                  │
  │                                      │  │                                  │
  │                                      │  │                                  │
  │                                      │  │                                  │
  ╰──────────────────────────────────────╯  ╰──────────────────────────────────╯

  ↑/↓ navigate  enter restore  ctrl-d/u scroll preview  esc back  esc×2 quit

The version view shows a list of versions on the left with a content preview on the right. Use ↑/↓ to navigate versions, Ctrl-d/Ctrl-u to scroll the preview, and Enter to restore a selected version.

You can also access version history from the browser's context menu by selecting Versions on any file.

SSM Parameter Store

ssm:// edits AWS Systems Manager Parameter Store parameters with the same edit → diff → confirm flow. Parameter Store has no buckets: the whole path after the scheme is the parameter name, normalized to a single leading slash, so ssm://myapp/db and ssm:///myapp/db both mean /myapp/db.

# Edit a parameter value in your editor
ladle ssm:///myapp/prod/db-url

# Read / write via pipes (agent- and script-friendly)
ladle ssm:///myapp/prod/db-url > value.txt          # read value to stdout
echo -n 'postgres://new/db' | ladle --yes ssm:///myapp/prod/db-url

# Create a new parameter (defaults to String; use --type for others)
echo -n 's3cret' | ladle --yes --type SecureString ssm:///myapp/prod/api-token

# List a path (directories keep a trailing slash); --recursive for the whole tree
ladle ssm:///myapp/prod/
ladle ssm:///myapp/ --recursive

# Version history (tab-separated: version, mtime, type, modified-by, LATEST)
ladle --versions ssm:///myapp/prod/db-url

# Parameter attributes as YAML (type, tier, keyId, description, dataType)
ladle --meta ssm:///myapp/prod/db-password
ladle --meta ssm:///myapp/prod/db-password > meta.yaml

SecureString safety

SecureString values are never exposed by default. Any operation that would reveal plaintext — editing, piping the value out, or diffing an update — refuses unless you pass --reveal:

ladle --reveal ssm:///myapp/prod/db-password          # decrypt and edit
ladle --reveal ssm:///myapp/prod/db-password > secret # decrypt to stdout

Notes:

  • On write, the original KMS key (keyId) and other attributes are preserved.
  • Editing a SecureString's metadata re-writes the parameter (SSM has no metadata-only API), so --meta on a SecureString also needs --reveal.
  • A SecureString value can still be updated non-interactively without --reveal by using --yes, which skips the (plaintext) diff (e.g. echo -n "$SECRET" | ladle --yes ssm:///myapp/prod/db-password).
  • Piping into a new parameter creates a String unless you pass --type (String | StringList | SecureString), so secrets aren't stored in cleartext by accident.
  • Temp files are created 0600 in a private directory and removed on exit.

Required IAM actions (scopable to the parameter / path ARN): ssm:GetParameter (read), ssm:GetParametersByPath (list & browse), ssm:GetParameterHistory (metadata & --versions), ssm:PutParameter (write), and ssm:DeleteParameter (browser delete / move); plus kms:Decrypt / kms:Encrypt on the key for SecureString.

Interactive directory URIs open the same TUI browser as S3 (tree navigation, / filter, and a context menu for edit / metadata / versions / download / copy / move / delete). A name that is actually a namespace (has children but is not itself a parameter) opens the browser too, so a missing trailing slash still works. When stdout is redirected/piped, a listing is printed instead. In the browser, SecureString values are masked in the version-preview pane unless --reveal is set.

Installation

Homebrew

brew install jingu/tap/ladle

From source

go install github.com/jingu/ladle/cmd/ladle@latest

From GitHub Releases

Download the binary for your platform from Releases.

AWS Options

ladle --profile production s3://bucket/file.html
ladle --region ap-northeast-1 s3://bucket/file.html
ladle --endpoint-url http://localhost:9000 s3://bucket/file.html   # MinIO
ladle --no-sign-request s3://public-bucket/file.html

Google Cloud Storage

ladle supports Google Cloud Storage via the gs:// scheme:

ladle gs://bucket/path/to/file.html
ladle gs://bucket/path/to/                     # file browser mode
ladle --project myproject gs://                # list buckets

Credentials are resolved via Application Default Credentials (ADC):

  1. GOOGLE_APPLICATION_CREDENTIALS pointing at a service account key file
  2. gcloud auth application-default login
  3. the attached service account when running on GCP (GCE, Cloud Run, GKE, etc.)
gcloud auth application-default login
ladle gs://bucket/file.html

Listing buckets (ladle gs://) requires a project ID, set via --project or the GOOGLE_CLOUD_PROJECT environment variable. Use --no-sign-request for public buckets, and --endpoint-url (or STORAGE_EMULATOR_HOST) to target the fake-gcs-server emulator.

Azure Blob Storage

ladle supports Azure Blob Storage via the az:// scheme, where the container maps to the bucket and the blob maps to the key:

ladle --account myaccount az://container/path/to/file.html
ladle az://container/path/to/file.html        # with AZURE_STORAGE_ACCOUNT set
ladle az://                                    # list containers

The storage account and credentials are resolved in this priority order:

  1. AZURE_STORAGE_CONNECTION_STRING — full connection string
  2. account name (--account or AZURE_STORAGE_ACCOUNT) + AZURE_STORAGE_KEY — shared key
  3. account name + AZURE_STORAGE_SAS_TOKEN — SAS token
  4. account name + Azure AD (DefaultAzureCredential, e.g. az login or Managed Identity)
export AZURE_STORAGE_ACCOUNT=myaccount
export AZURE_STORAGE_KEY=...                  # or
export AZURE_STORAGE_CONNECTION_STRING=...    # or just `az login` for Azure AD
ladle az://container/file.html

Use --endpoint-url to target the Azurite emulator.

Flags

Flag Short Description
--meta Edit object metadata instead of file content
--versions Show version history for a file (S3 / GCS / Azure Blob versioning)
--editor Editor command (overrides env vars)
--yes -y Skip confirmation prompt
--dry-run Show diff without uploading
--force Force editing of binary files
--reveal Decrypt and expose SecureString values (ssm://)
--recursive List parameters recursively (ssm://)
--type Type when creating a new ssm:// parameter (String|StringList|SecureString)
--profile AWS named profile
--region AWS region
--account Azure storage account name (or AZURE_STORAGE_ACCOUNT)
--project GCP project ID for bucket listing (or GOOGLE_CLOUD_PROJECT)
--endpoint-url Custom endpoint URL (MinIO, LocalStack, Azurite, fake-gcs-server, etc.)
--no-sign-request Do not sign requests
--install-completion Generate shell completion script (bash|zsh|fish)

Editor Resolution

ladle selects an editor in this order:

  1. --editor flag
  2. LADLE_EDITOR environment variable
  3. EDITOR environment variable
  4. VISUAL environment variable
  5. vi (fallback)

Shell Completion

# bash
ladle --install-completion bash >> ~/.bashrc

# zsh
ladle --install-completion zsh >> ~/.zshrc

# fish
ladle --install-completion fish > ~/.config/fish/completions/ladle.fish

Agent Skill

ladle ships an Agent Skill that teaches AI coding agents how to read, edit, and inspect cloud storage objects with ladle (using pipe mode so it works non-interactively).

# Install for Claude Code (user-global: ~/.claude/skills/ladle/SKILL.md)
ladle skill install

# Install into the current project (.claude/skills/ladle/SKILL.md)
ladle skill install --project

# Overwrite an existing install
ladle skill install --force

# Print the skill to stdout
ladle skill show

Future Plans

  • Cloudflare R2 (r2://) backend
  • Multi-file batch editing
  • ladle compare for diffing two remote files

License

MIT

About

CLI tool to edit S3/cloud storage files with your local editor — download, edit, diff, upload

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors