SuperAPI AI Directory

package-neon-green

Deployment & operations

View repository

Updated 10-16 07:25

About this skill

Neon Package Skill (Green)

Provisions one Vultr instance running the Neon storage tier (storage broker, pageserver, one safekeeper) and a Postgres compute node, with pageserver layers and safekeeper WAL uploaded to Cloudflare R2 under the deployment's own prefix, and OpenTofu state in R2.

Install the launcher

npx skills add getcolors/neon
cp .agents/skills/package-neon-green/green ./green
chmod +x green

The root green is a copy of the payload, not a symlink. npx skills update -p rewrites the payload and leaves the copy alone, so copy it again after every update or the project keeps running the old pin.

Verbs

./green build              # render .colors/<profile>/ — no provider calls, no credentials
./green create --dry-run   # walk the workflow, skip every side effect
./green create             # converge for real
./green delete             # guarded and destructive

build and --dry-run are the safe way to check a colors.yml edit: they work on a fresh checkout with an empty environment. Exit code 2 is a validation or usage failure and lists every problem at once. The launcher walks up from the working directory to find colors.yml, so any subdirectory works.

Rules that are not negotiable

  • colors.yml is the only file you edit. Kebab-case keys, non-secret values only.
  • Credentials are COLORS_PAR_* environment variables in a gitignored .envrc.private. Never in colors.yml, generated output, or documentation.
  • Never export COLORS_PAR_PROFILE. The profile keys remote state; the package refuses to run when it is set, and that refusal is the guard working.
  • .colors/ is generated output. Never edit it, never read it as source, never commit it.
  • delete is guarded by compute-prevent-destroy: true, liftable only with COLORS_PAR_COMPUTE_PREVENT_DESTROY=false for one run. Never edit the committed flag. Never run a real create or delete against a live deployment without explicit authorization.

What it builds

Stage What it manages
neon-infrastructure one Vultr instance, a firewall opening 22 only, and in keygen mode the account SSH key named after the profile
neon-ssh-config the ~/.ssh/config block, so ssh <profile> works
neon-ansible Docker Compose: the storage broker, the pageserver, one safekeeper, and the compute node — plus tenant/timeline reconciliation and the server-side acceptance gates
acceptance the operator path: an SSH tunnel through the generated alias, a psql round-trip with the generated password, and a refused wrong password

Connecting

Nothing is published beyond loopback; there is no DNS record and no public 5432. The supported client path is the tunnel:

ssh -L 55433:127.0.0.1:55433 <profile>
psql 'postgresql://<neon-role>@127.0.0.1:55433/<neon-database>'

The role's password is generated on the server: ssh <profile> cat /etc/neon/secrets/neon_role_password. neon-status on the host summarizes container, tenant and timeline state; neon-rotate rotates the role password atomically, with rollback.

Durability, honestly

The pageserver uploads layers and the safekeeper offloads closed WAL segments to R2 under <profile>/data/. Commit acknowledgement still requires the host's disk, uploads are asynchronous, and a fresh safekeeper cannot serve offloaded WAL back — so a full host loss recovers what the pageserver had uploaded: the single-node RPO is the activity since its last checkpoint upload. A wiped storage tier on a surviving host loses nothing (rehearsed). This is a demo-tier deployment and says so. Never configure R2 lifecycle rules on the bucket: they would delete live layers and WAL.

Reference

references/configuration.md documents every colors.yml key, every credential, and the recovery procedure.

Compute is delegated to the pinned colors-compute library. Its singleton topology preserves SSH-only public ingress and loopback application services. R2 or S3 state lives under <profile>/compute/shared.tfstate and <profile>/compute/nodes/0.tfstate, with a deployment journal; local compute state is unsupported. Existing <profile>/neon-infrastructure.tfstate is refused for explicit operator migration, never silently adopted. Build renders shared/node plans with their remote backend configuration.

The package owns a locked profile SSH alias updater. Managed keys add IdentityFile ~/.ssh/<profile>; external private paths are explicit Ansible/acceptance inputs. The alias is removed before compute destruction. Application images, data-prefix ownership markers, generated passwords, and acceptance gates are unchanged. No live deployment was performed for this migration.

Validated retired compute prevents remote Ansible during delete even when caller input retains a stale IP or private-key path. Remaining application and local cleanup keeps its existing ordering. Normal creation still converges the application.