A remote development machine, with Walter
Use this skill to initialize or operate a walter project in the user's current
directory. Walter provisions one machine, records it in
so
reaches it, and powers it off and on.
Requirements
Babashka runs the launcher.
and
also need OpenTofu and
Ansible.
and
need the
CLI and a live session. With
set, a real
also needs
on the workstation — it
runs GitHub's device flow as its first action. Provider credentials use
variables, except OCI, which uses the profile named in
, and S3, which uses OpenTofu's ambient AWS credential chain.
Non-negotiable safety rules
- Never ask the user to paste a secret into chat.
- Never put API tokens, passwords, private keys or access keys in ,
in the launcher, in shell history, or in generated examples. Every
credential arrives through a environment variable named after
the key it fills. Suggest a gitignored , never an inline
export a shell history records.
- Public SSH keys are not secrets; private ones are.
holds the path to a public-key file that OpenTofu reads at plan time —
record the path, never inline the contents, and never read a private key.
With walter generates and manages
itself; never read or move that file either.
- With set, a real starts by printing a one-time
code and waiting — up to about fifteen minutes — for the user to approve it
at https://github.com/login/device. That is the design, not a hang: the
workflow is interactive at the beginning only. Relay the code and URL to the
user and wait; never try to acquire, read, or echo the token itself.
- Never set . Walter refuses to run when it is set, and
suggesting it as a workaround defeats the guard. The profile identifies the
project, and the project is the directory. If the user wants a different
profile, edit .
- Do not overwrite an existing launcher or without
explicit approval. If a project is already valid, operate it rather than
regenerating it.
- Default to and . Run a real or
only after the user confirms that exact operation.
- and are credential-free by design and check no
at all. A clean dry-run says nothing about whether real
provisioning would authenticate; never report it as credential validation.
- Before , remind the user that a development machine holds uncommitted
work and that the boot volume goes with it. defaults
to ; authorize an intentional delete with
COLORS_PAR_COMPUTE_PREVENT_DESTROY=false
rather than editing desired state.
- Never edit anything under — it is generated output.
Read
references/configuration.md before
generating or changing desired state, and before any real
or
.
Commands
sh
./green build # render .colors/<profile>/ only; contacts nothing
./green create --dry-run # print the graph; touches nothing
./green create # provision, and write the ssh config block
./green stop # power off
./green start # power on, and refresh the ssh config block
./green delete # destroy, dropping the ssh block first
overrides the
found by walking up from the working
directory.
Initialize in the current directory
- Copy the payload beside this file into the project root and
it.
- Write . Ask for the provider first, then only the keys that
provider needs —
references/configuration.md
lists them.
- Choose a unique to this project, conventionally the directory
name. It names the work directory, the OpenTofu state keys and the ssh alias.
Two projects sharing a profile and a state bucket address the same state,
which is how a development machine ends up managing a production server.
- Ask whether the machine should have the user's GitHub identity. If so, set
to their login and to their commit email, and
tell them a real will start with a one-time device-flow code to
approve from a browser. This is required before offering
, or — their clones
authenticate through it.
- Ask whether walter should generate the machine-access ssh keypair
() or whether the user supplies a provider key as
before.
- Ask whether the user wants their Emacs configuration on the machine. If so,
set to its https git URL (/ forms are
refused) and to where it must live — the default is
, and a configuration expecting another path needs
to reach it. Leave both out otherwise; the rendered
playbook then does not mention Emacs.
- Run and show the user what was rendered.
What create puts on the machine
Every machine gets
nix, a
Ghostty terminfo entry, and kernel networking
settings for unprivileged
, unconditionally. The sysctls allow the
login user's primary group to use ping sockets and raise QUIC's receive/send
buffer ceilings, so a tunnel should run without sudo or those warnings. Tell
the user about nix rather than proposing walter changes for other tooling: once
it is there, anything else is
and needs nothing from
walter.
The terminfo is why
Terminal type xterm-ghostty is not defined
does not
happen. If a user reports that error — from
,
,
or Emacs — on a
machine created before this existed, the fix is to re-run
, not to
change
. For a terminal walter does not cover, the one-liner is:
sh
infocmp -x "$TERM" | ssh <alias> -- tic -x -
With
set,
also logs the machine's own gh in with the
token the device flow minted, makes it git's https credential helper, and
configures the commit identity — every clone below authenticates through it,
and nothing of the workstation's (no key, no agent) is involved. A machine
already logged in skips the interactive step entirely, so re-creates stay
unattended.
With
set,
also installs Emacs (a full build from a
pinned nixpkgs) and clones the configuration over https with the machine's own
token — no private key is written to the machine, and the checkout can push
back. The clone happens
once; a later
leaves an existing one alone,
so work done on the machine is never discarded. Offer
on the machine
rather than a re-run when the user wants the config refreshed.
Emacs packages are not pre-fetched. The first
launch fetches from
ELPA/MELPA, native-compiles and clones tree-sitter grammars, which takes minutes
and is expected. Do not report it as a provisioning failure.
and
reach
via
, a
login shell
mechanism:
sees them,
as a one-shot
command does not.
Stopping and starting
and
never reach OpenTofu. No template declares a power state, so
powering the machine off out of band causes no drift — there is nothing for
OpenTofu to reconcile.
Consequences worth telling the user about:
- Only OCI can be power cycled today. Everywhere else reports that
and exits 0. That is deliberate, not a bug. Do not present it as a failure.
- will not restart a stopped machine. With no power state in the
configuration there is no diff, so an apply leaves it stopped. is the
only way up.
- Stopping stops the compute meter, not the storage one. The boot volume
bills whether the machine runs or not.
- and need the CLI to authenticate, which OpenTofu does
not. Session tokens last 60 minutes. When walter reports an expired session it
names the command that fixes it; run that, then retry.
When something fails
COLORS_PAR_PROFILE is set
— the user has it exported, probably from
another project's . Unset it; do not work around it.
required credential is not set: COLORS_PAR_X
— name the variable and let
the user export it themselves.
- — walter could not read the compute stage's
output and desired state carries none. Either the machine was never created,
or the state backend is unreachable. in is the
documented escape hatch.
- — is missing on the workstation, or the
one-time code expired unapproved. Install gh or re-run and approve
the code; there is no token to paste anywhere.
- A create failed after the code was approved — just re-run it. The minted
token survives under
~/.local/state/walter/github-token-<profile>
for
exactly this, so the retry does not prompt again; it is removed once a
create seeds the machine.
- the login approved the code as X but colors.yml names github-account Y —
the user approved from the wrong GitHub account. Re-run and approve
from the account the machine is meant to act as, or fix .
- A contract mismatch — the pinned commit is older than this launcher.
Re-copy from an updated skill; nothing inside the project fixes it.