Metadata-Version: 2.4
Name: boxman
Version: 0.1.6
Summary: Set up and manage an Ubuntu development box
Project-URL: Homepage, https://github.com/vivainio/boxman
Project-URL: Documentation, https://vivainio.github.io/boxman/
Project-URL: Repository, https://github.com/vivainio/boxman
Project-URL: Issues, https://github.com/vivainio/boxman/issues
Keywords: ubuntu,development,ec2,cloudformation,cli
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Systems Administration
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Provides-Extra: ec2
Requires-Dist: boto3>=1.34; extra == "ec2"

# boxman

[Read the Boxman book](https://vivainio.github.io/boxman/) for the concepts, setup steps, and command reference.

Set up and manage an Ubuntu 24.04 development box. `boxman` is a Python command
with system, user, and vault operations.

## Install a host

From this checkout, run the system step as root, then the user step from each
login account. The first command works with the Ubuntu system Python before
`uv` is installed:

```bash
sudo boxman system
boxman user
```

Install the published command with uv:

```bash
uv tool install --upgrade boxman
boxman vault status
```

For local development, use `uv tool install --editable .` from this checkout.

`boxman system` installs the apt packages declared in
`linux-tools.toml`, sets up Git LFS, and configures rootless Podman for normal
login users. It accepts explicit usernames, or `--packages-only` for a
container build. It installs the recipe's `[system_packages]` apt list with
`apt-get`.

`boxman user` installs the tools in the recipe, Node.js 22, Claude Code,
Copilot CLI, and uv. Run the user step for each account.
Run `boxman verify` afterward to check the installed commands and rootless
Podman.

The same package set can be used in a dev container:

```bash
podman build -f container/Dockerfile -t boxman-dev .
```

The container build skips host login-user and systemd configuration. FUSE
mounting may require additional container privileges, so the vault commands
are intended for the native host.

## Private directory

The recipe installs `gocryptfs` and FUSE 3. Each user initializes their own
vault once and unlocks it after a reboot or unmount:

```bash
boxman vault init
boxman vault unlock
boxman vault status
boxman claude  # starts Claude with its config in the mounted vault
boxman vault lock  # after stopping processes that use the mount
```

Encrypted files live in `~/.private.cipher`; the plaintext mount is
`~/private`. Initialization and unlocking prompt for the password. Keep the
password and gocryptfs recovery key outside the host. Back up the encrypted
directory, including `gocryptfs.conf`, while keeping the plaintext mount out
of backups.

`boxman claude` refuses to run unless the vault is mounted. Use it before the
first Claude login. It sets `CLAUDE_CONFIG_DIR` to `~/private/claude` and does
not move existing credentials from `~/.claude`. Configure other tools'
credential locations separately if they should use the vault. Persistent
agents need the vault mounted while they use credentials. Locking fails while
a process holds files in the mount open.

The vault protects its backing files and snapshots while locked. It does not
hide credentials from the user's running processes or a host administrator
while unlocked. Keep home directory permissions private to each Unix owner.

## EC2 host

Install the optional AWS dependency, then create
`${XDG_CONFIG_HOME:-~/.config}/boxman/layout.yaml`:

```bash
uv tool install --upgrade 'boxman[ec2]'
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/boxman"
```

```yaml
ec2:
  machine: red
  user: your-user
  profile: your-aws-profile
  region: your-region
  tags:
    Owner: your-owner
    Environment: development
```

The config contains no credentials; AWS uses the named profile. Supply the tags
required by your account. The `ec2` map selects the AWS profile, region, stack
and tags. Command-line options override the file;
`--tag KEY=VALUE` adds or overrides a tag. `--config FILE` selects another layout file (see docs/ec2.md). Put global options before the action:

```bash
boxman ec2 --profile your-aws-profile discover   # JSON: VPCs, subnets, instances, tags
boxman skill                                      # print a getting-started skill for AI agents
boxman ec2 --machine red init --vpc-id vpc-... --subnet-id subnet-... \
  --instance-type t3.xlarge --volume-size-gb 100 \
  --instance-name mybox \
  --ami-id /aws/service/canonical/ubuntu/server/24.04/stable/current/amd64/hvm/ebs-gp3/ami-id
boxman ec2 deploy
boxman ec2 status                         # uses default_machine (red)
boxman ec2 --machine blue status
boxman ec2 start
boxman ec2 stop
boxman ec2 destroy   # deletes the stack, instance and volume
boxman ec2 connect -u myuser
boxman ec2 setup --user alice
boxman ec2 ssh -u myuser
boxman ec2 ssh-config -u myuser --herdr
boxman ec2 run -u myuser 'uname -a'
boxman ec2 --machine red secrets send ./secrets.json -u myuser
```

`init --machine red` writes `${XDG_CONFIG_HOME:-~/.config}/boxman/stacks/red.yaml`
and derives the CloudFormation stack name `boxman-red`. It includes the
instance settings as parameter defaults and refuses to overwrite an existing
file. Edit that YAML to customize the stack. `deploy` reads the YAML for the
selected machine and sends its defaults as CloudFormation parameters. Tags from `[machines.red.tags]` and repeatable
`--tag KEY=VALUE` options become CloudFormation stack tags. A single config
file can describe red, blue, and green boxes; use `--machine NAME` to select
one, or set `[ec2].default_machine` for the default.

Deployment creates or updates a CloudFormation stack containing an Ubuntu EC2
instance, an SSM role, and an EC2 Instance Connect Endpoint. SSH uses that
endpoint and sends a short-lived public key through EC2 Instance Connect before
opening SSH. `ssh-config` writes a marked host entry to `~/.ssh/config`; its
alias defaults to the machine name. Pass `--herdr` to prepare the remote Herdr
server and save the same SSH machine with `herdr machine add`. `setup --user USER`
uses the Ubuntu image's `ubuntu` account by default as the bootstrap account,
creates `USER` if needed, and uses that SSH path to stage Boxman remotely and
run the system, user, and verify steps. Pass `--bootstrap-user ACCOUNT` for a
custom image. The machine name selects the instance for
all subsequent commands. Starting, stopping, and deploying incur AWS charges.

## Remote secrets

Keep a JSON object of string secrets on your laptop in a file readable only
by you (`chmod 600 secrets.json`). Upload it to the selected machine:

```bash
boxman ec2 --machine red secrets send ./secrets.json -u alice
```

The remote `boxman secrets receive` command loads the document into the
default tempkeys keyset in Alice's Linux user keyring. On the host,
`boxman secrets read NAME` prints one value; `tempkeys list --set default`
lists names, and `tempkeys clear` removes the keyset. Names must be
environment variable names and values must be nonempty strings. Any process
running as Alice can potentially read these values. Kernel keyrings do not
survive reboot, so resend the document from the laptop after a restart. Keep
the laptop copy as the source of truth. `boxman user` installs the tempkeys release binary from GitHub and configures Git to read `GH_TOKEN` through its
credential helper for HTTPS `github.com` remotes. A `git push` fetches the
token when Git needs it; it is not put in the shell environment. GitHub CLI
commands still need `tempkeys --user run -e GH_TOKEN -- gh ...` or another
GH_TOKEN environment setting. Secrets stored by the earlier Boxman format need to be
resent after upgrading; tempkeys uses a different file format.

## Release

Build the Zensical book locally with `zensical build --clean`. The docs workflow
publishes it to GitHub Pages when documentation changes on `main`.

A published GitHub release triggers the PyPI workflow. Use a `vX.Y.Z` tag;
the workflow sets the package version from the release tag, builds the wheel
and source distribution, and publishes with PyPI trusted publishing. Configure
a PyPI trusted publisher for repository `vivainio/boxman`, workflow
`publish.yml`, environment `pypi` before the first release.
