# Using PowerCloud with an AI assistant

> How an AI coding assistant such as Claude Code should read these docs, run pcctl safely, handle secrets, and which commands need a person's go-ahead.

PowerCloud has no login and no shell on its nodes: everything happens through `pcctl`, a single command-line program. That makes it a good fit for an AI assistant working in your terminal, such as Claude Code. The assistant runs the same `pcctl` commands you would, reads their output and explains what it sees. This page is for both of you: the person setting the assistant up, and the assistant itself.

## Point the assistant at the docs

Every page of this documentation is also published as plain Markdown, written to be read by machines as well as people:

| URL | What it holds |
|---|---|
| `https://powercloud.unidatum.com/llms.txt` | An index of every page, with a one-line summary each |
| `https://powercloud.unidatum.com/llms-full.txt` | Every page in one file, for loading the whole manual at once |
| `https://powercloud.unidatum.com/docs/SLUG.md` | One page as Markdown, for example `/docs/pcctl.md` |

The [pcctl reference](https://powercloud.unidatum.com/docs/pcctl.md) lists every command and flag. When the assistant is unsure about a command, it should read that page rather than guess flags. `pcctl` itself prints a usage summary when it is run with no arguments.

## Add PowerCloud to your project's instructions

Assistants read a project instructions file at the start of each session: `CLAUDE.md` for Claude Code, `AGENTS.md` for many others. Paste this into it, and adjust the first two lines to your cluster:

```text
## PowerCloud
- This project's cluster is managed with pcctl. Nodes: node-1, node-2 (see `pcctl node ls`).
- Storage locations: set in POWERCLOUD_REPO by the person, never written in this file.
- Docs: https://powercloud.unidatum.com/llms.txt (index), /docs/pcctl.md (command reference).
- Start with `pcctl status` to see the cluster before changing anything.
- Never ask for, print, store or commit the cluster passphrase, the recovery key,
  enrollment codes, join bundles or anything in the pcctl config directory.
- Commands that need the passphrase: give the person the exact command to run in
  their own terminal, unless POWERCLOUD_PASSPHRASE is already in your environment.
- Ask before: node rm, gc, rm, rotate, revoke-admins, release publish, node upgrade,
  node poweroff/reboot, app rm, cluster app rm, s3 key rm, s3 disable, node tpm off.
```

Before running any `pcctl` command, the assistant decides like this:

```mermaid
%% alt: Before running a pcctl command, an assistant runs read-only commands freely, asks a person to confirm anything on the confirm list, and has the person run any command that needs the passphrase.
flowchart TB
  start["About to run a pcctl command"] --> q{"What kind<br/>of command?"}
  q -->|"read-only,<br/>no secret"| run["Run it"]
  q -->|"on the<br/>confirm list"| ask["Describe it,<br/>wait for a yes"]
  q -->|"needs the<br/>passphrase"| person["The person runs it in their own terminal"]
  ask --> after["Then run it, or hand it over if it needs the passphrase"]
```

## What the assistant can do without any secret

Once a person has enrolled a node or run `pcctl --repo ... login`, `pcctl` holds an admin certificate in its config directory, and these commands work with no passphrase. They only read, so the assistant can run them freely to find out what's going on:

```sh
pcctl status                 # every node, and what needs attention
pcctl node ls
pcctl node info NAME
pcctl app ls NODE
pcctl app logs NODE NAME
pcctl release status
pcctl consensus status
pcctl kv get KEY             # and: pcctl kv ls [PREFIX]
pcctl s3 status
pcctl s3 key ls
pcctl version
```

A good first step in any session is `pcctl status`, then `pcctl node info NAME` for any node it flags.

## Commands that need the passphrase

Commands that open the cluster's storage need the cluster passphrase. That covers everything given `--repo` or `--via`: `put`, `get`, `ls`, `rm`, `check`, `repair`, `gc`, `login`, enrolling, provisioning and removing nodes, `node unlock`, `node tpm`, `node peer-unlock`, `node attest NAME sev-snp|off`, `node renew`, `node storage`, `mesh`, `rotate`, `release publish`, `cluster app`, `consensus init`, `s3 enable` and `s3 key add`.

`pcctl` asks for the passphrase on the terminal. An assistant usually runs commands without a terminal, so `pcctl` stops with:

```text
pcctl: no terminal for passphrase; set POWERCLOUD_PASSPHRASE (and POWERCLOUD_NEW_PASSPHRASE for rotate)
```

When the assistant sees this, it should not ask for the passphrase in the chat, because whatever is typed there is stored in the conversation. Do one of these instead:

- **The person runs the command.** The assistant shows the exact command and the person runs it in their own terminal, then shares the output if it's useful.
- **The person exports the variable before starting the assistant.** Many assistants, Claude Code among them, run each command in a fresh shell, so a variable set in one command is gone by the next (and the assistant must not be the one typing the passphrase). Instead, in your own terminal, set it (for example `read -rs POWERCLOUD_PASSPHRASE && export POWERCLOUD_PASSPHRASE`, which keeps it out of shell history) and start the assistant from that same shell, so every command it runs inherits it. Every one of those commands can then read the passphrase, so do this only on a machine you trust, for one session, and never write it to a file in the project.

Whichever way you choose, the person runs `pcctl init` themselves: it prints the recovery key once, and anything a command the assistant runs prints becomes part of the conversation. For a step-by-step guide to deploying with Claude Code, see [Deploying a design with Claude Code](https://powercloud.unidatum.com/docs/claude-code.md).

`POWERCLOUD_RECOVERY_KEY` unlocks the cluster in place of the passphrase. It is meant for emergencies only, and an assistant should never be given it.

## Secrets the assistant must never handle

| Secret | Where it appears | Why it matters |
|---|---|---|
| Cluster passphrase | Typed at `pcctl` prompts, or `POWERCLOUD_PASSPHRASE` | Opens every byte of the cluster's data |
| Recovery key | Printed once by `pcctl init` | Same power as the passphrase, and it can't be changed except by `pcctl rotate` |
| Enrollment code | A new node's console | Lets whoever has it enroll the node into their own cluster |
| Join bundle (`NAME.join`) | Written by `pcctl node provision` | Holds the node's private keys and its disk key |
| pcctl config directory | `~/.config/powercloud` on Linux, `~/Library/Application Support/powercloud` on macOS, or `POWERCLOUD_CONFIG` | Admin certificate and key: full control of the nodes |
| S3 secret keys | Printed once by `pcctl s3 key add` | Read, and possibly write, access to the gateway |
| Storage credentials | `NAME_ACCESS_KEY_ID`, `NAME_SECRET_ACCESS_KEY` in the environment | Access to the encrypted data at the provider |

The assistant shouldn't `cat` these files, echo these variables, put them in commit messages or code, or copy them into other files. Keep `*.join` files and the config directory out of version control, with a `.gitignore` entry, for example.

## Commands to confirm with a person first

`pcctl` doesn't ask "are you sure?". It does what it's told straight away. An assistant should describe what it is about to do and wait for a yes before running any of these:

| Command | Effect |
|---|---|
| `node rm [--erase] NAME` | Revokes the node for good, and with `--erase` wipes its disk |
| `rm NAME`, `gc` | Delete data (`gc --dry-run` is safe and shows what would go) |
| `rotate`, `rotate finish` | Change the cluster's keys and passphrase |
| `revoke-admins` | Invalidates every admin certificate, including other people's |
| `release publish` | Rolls a new image out to every node, one at a time |
| `node upgrade NAME FILE.efi` | Reboots the node into a new image |
| `node poweroff NAME`, `node reboot NAME` | Takes the node and its apps down |
| `node tpm NAME off`, `node peer-unlock NAME off` | The node then needs a person to unlock it after each reboot |
| `app rm`, `cluster app rm` | Stop and remove apps |
| `s3 key rm`, `s3 disable` | Cut off S3 clients |
| `init` | Creates a new cluster in the given locations |

Read-only commands and `--dry-run` runs never need confirmation.

## Reading pcctl's output

- Output is plain text meant for people, not JSON. Parse it loosely, and prefer asking `pcctl` again over guessing from partial output.
- The exit status is 0 on success, 1 on an error, and 2 on a usage mistake. Errors are printed as one line starting `pcctl:`, and many end with the command that fixes them in brackets. For example, an expired certificate suggests `pcctl --repo ... node renew NAME`.
- Long operations such as `node upgrade` and `release publish` wait and report progress as they go. Let them finish. Interrupting one doesn't undo it, and a node mid-upgrade rolls back by itself if the new image fails.
- [Troubleshooting](https://powercloud.unidatum.com/docs/troubleshooting.md) lists the common errors and their fixes.

## A worked example

You ask: "Why is the photos app down?" A careful assistant:

1. Runs `pcctl status` and sees that node-2 needs attention because it is locked after a reboot.
2. Runs `pcctl node info node-2` to confirm, and `pcctl app ls node-2` to see which apps were there.
3. Explains that node-2 rebooted and is waiting to be unlocked, and that unlocking needs the passphrase. It shows you `pcctl --repo ... node unlock node-2 CODE` to run yourself, or suggests `pcctl --repo ... node tpm node-2 on` for unattended unlock in future, after reading [Unlocking nodes](https://powercloud.unidatum.com/docs/unlock.md).
4. After you've unlocked it, runs `pcctl app logs node-2 photos` to check that the app is back.

At no step does it need, see or store the passphrase.
