borescope v1 · under active development

A shell for the containers that have no shell.

Kubernetes charm workloads run a rock with no shell. When something breaks, juju ssh --container=workload drops you nowhere useful. borescope gives you a prompt that feels like bash, talking to the container's Pebble through the Juju authority you already have.

Apache 2.0 · free & open source

A debug shell that meets the rock where it is

No shell in the image, no kubectl, no cluster-admin. Just the prompt you wish juju ssh gave you.

Works on rocks with no shell at all

The workload rock has no bash, no coreutils, often nothing. borescope drives the workload's Pebble through the charm container, which always has a shell, so the familiar file commands work even when the image is empty.

pebble:/# ls /var/log/myapp
app.log  errors.log  audit/
pebble:/# grep -c ERROR errors.log
42

Pebble's vocabulary, first-class

services, logs, plan, checks, changes, notices: Pebble's own commands are built in, not hidden behind a pebble prefix. Start and stop services, follow logs, read the merged plan.

pebble:/# services
pebble:/# logs --follow myapp
pebble:/# plan

Your Juju authority, nothing more

borescope reaches the container with juju ssh, exactly as you would by hand. If you can juju ssh to the unit, borescope works. If you can't, it fails the same way. No kubeconfig.

Feels like bash

A real REPL with cd and pwd, path-aware tab-completion, history scoped per unit, single pipes (logs | grep error), and the familiar file commands. Muscle memory mostly just works.

An exec escape hatch

borescope ships a deliberately small command set. Anything it doesn't cover, exec <tool> runs directly in the container with your current working directory.

One-shot and snapshot modes

Script it with --command "services": runs once and exits. File a bug with --snapshot: services, plan, checks, notices, and recent logs as a single stable JSON document.

How it works

Three thin, independently-testable layers.

  1. Discover the right Pebble

    borescope turns myapp/0 into a target: it confirms the unit, reads the charm's metadata.yaml for workload container names, and checks the container is alive, all over your Juju model access.

  2. Open a transport

    The default backend reaches the workload's Pebble socket through the charm container via juju ssh. When the socket is directly reachable, inside a charm or a local Pebble, it uses the real ops.pebble.Client HTTP API instead.

  3. Drop you at a prompt

    A small REPL maps familiar commands onto Pebble's files and exec APIs. Pebble's own vocabulary is first-class. exec covers the rest.

Built on the Canonical ecosystem

borescope is a thin layer over tools you already run.

  • Jujuorchestration & authority
  • Pebbleprocess supervisor
  • OpsPebble API
  • RockcraftOCI images
  • Canonical K8sKubernetes

Get started in seconds

Install from a checkout while v1 is under active development. Stable snap and PyPI releases are coming.

Terminal
# Install from a checkout
$ uv tool install .          # or: pipx install .

# Open a prompt on a unit's workload container
$ borescope myapp/0
pebble:/# services
pebble:/# logs --follow myapp
pebble:/# tail -f /var/log/myapp/error.log
pebble:/# exec ps aux
pebble:/# exit

# One-shot, for scripts
$ borescope myapp/0 --command "services"

# Dump container state as JSON
$ borescope myapp/0 --snapshot

borescope picks up your current Juju controller and model, just like the juju CLI. Point it at a different model with --model, choose a workload with --container, or run it inside a charm container with --here.

Several ways to drive it

Interactive REPL

A bash-like prompt with history, tab-completion, and pipes against a single unit.

borescope myapp/0

One-shot

Run a single command and exit, for scripts, aliases, and CI.

borescope myapp/0 -c "plan"

Snapshot

A stable JSON dump of container state, ideal for bug reports and tooling.

borescope myapp/0 --snapshot