Repository navigation
feat!: make pier great again - #40
Merged
Merged
Conversation
Bake now checks the repo out on the bake instance, runs .pier/setup.sh to completion, scrubs everything the create cargo delivered, and images the result. The bootstrap reuses a checkout it finds, so sessions from the image fetch only the delta and re-run setup warm. AWS launches from baked images request provisioned-rate volume initialization, falling back when the CLI predates the field. Create, claim and fill progress lines carry elapsed time.
pkg/pier is now the one API the CLI, the TUI and the coming Mac app use. It owns every capability behind a Client, reports long operations as typed events, returns typed errors, and never prints, exits or reads stdin. Drivers no longer write to the terminal: transfer meters, streamed bake output and transport notices go through fields the frontend sets. Session images are one concept. `pier bake` prebuilds the repo by default and records what it baked from, so pier can remind — never decide — when a rebake would help. Speed profiles (fast, lean, minimal) preset how many ready sessions a baked repo keeps and whether reminders show. Setup shows every default for confirmation and offers to bake the repo it runs in. Settings is one page grouped by cloud, new sessions, idle and cost, and speed, showing only the active cloud. The app has Sessions, Repos and Settings tabs, titled panels, a detail pane and a live cost header. BREAKING CHANGE: `pier pool` is replaced by `pier ready [n]` and `pier repos`, `pier skills` by `pier setup --skills`, and `--no-pool` by `--no-ready`. Baked repos keep one ready session by default.
Parking is a shutdown, so a wake used to land in a fresh tmux server with
an empty shell. The supervisor now snapshots the agent user's tmux every
~30s and right before it parks (~/.pier/tmux: state.json plus per-pane
scrollback), and a new pier-restore.service runs `pier-supervisor restore`
once per boot to rebuild it: sessions, windows, layouts, cwds, replayed
scrollback, claude relaunched with --resume <id> or --continue, codex with
`codex resume --last`, other commands typed at the prompt but not run, and
setup windows as a plain shell. Attach waits briefly for its marker. Pool
claims and the prebuild scrub drop the saved layout.
Deviations from the design:
- Agents start from a one-shot PROMPT_COMMAND in the restored shell, not by
exec'ing the agent from the pane command. Startup files run before bash
enables job control, so a program started there shares the shell's
process group: tmux reports "bash" as the pane command and Ctrl-Z can't
reach the agent. Quitting the agent also leaves a shell, not a closed pane.
- The restored shell reads a generated rcfile instead of being a login shell
(it sources /etc/profile and ~/.profile itself). pier's ~/.bashrc cd's
into the repo, which would override the pane's saved cwd.
- Typed-back commands wait until the pane's tty leaves canonical mode
(readline is reading). Keys sent earlier are echoed by the tty and then
again by readline.
- The list-panes separator is printable ("|pier|"): tmux 3.2 (Ubuntu
22.04) rewrites tabs in format output as '_'.
- Freshen waits (bounded) for the restore marker before killing the server,
so a restore still in flight can't start a server after the kill.
- Both units set RuntimeDirectoryPreserve=yes so a supervisor restart does
not delete the /run/pier/restored marker they share.
- A few claude flags (--dangerously-skip-permissions, --model,
--permission-mode) carry over to the relaunch, so an unattended agent
isn't left waiting on permission prompts. A positional prompt never
carries over.
… resume A pane whose root process is the program itself (tmux ran claude directly) was saved as the first child in its process group — one of claude's MCP servers — so a wake typed that command back instead of relaunching claude. Children are only searched when the pane's root is a shell. A claude or codex pane with no conversation to resume made --continue exit with an error and left a bare shell; the relaunch now falls back to a fresh agent.
setup.sh builds an environment; start.sh brings a built one up, the way a laptop runs `docker compose up` after a reboot rather than a fresh install. Sessions from a prebuilt image and ready-session claims now run start.sh when the repo has one, instead of re-running the whole setup, and a parked session's boot runs it after the tmux restore, so it wakes with its services running. All three go through one session-up script the bootstrap writes (modes setup, warm, wake); parked ready sessions skip the wake start because their claim runs it. Restore no longer brings back pier's own setup and start windows: their run is over, `pier logs` keeps the output, and a wake starts a fresh one. The shell rc only moves a login into the repo when it starts in $HOME, so new tmux windows and splits keep the folder they were opened in; older images get the line rewritten at first boot.
Setup runs when a session is built and never again. A ready-session claim resumes, checks out the branch and refreshes secrets without re-running it, and a wake re-runs nothing. What a wake needs is what was running: the supervisor records the running Docker containers with each tmux snapshot and before it parks, and the first supervisor of each boot starts exactly those again once the daemon answers — any repo, no extra file. BREAKING CHANGE: `.pier/start.sh` is no longer read.
The pool keeps its name. `pier pool` shows it, `pier pool set <n>` sizes it, `pier pool fill` tops it up now and `pier pool drain [repo]` empties any repo's pool from anywhere; fills still also happen by themselves after every create and size change. The app's Repos tab has the same actions: +/- sets the size, f fills, x drains. The speed setting is speed.pool_size; configs that stored it under its interim name are read as before. BREAKING CHANGE: `pier ready` is replaced by `pier pool`, and `--no-ready` by `--no-pool`.
A row shows one word per session — starting, running, parked, deleting or create failed. The supervisor's activity reading (attached, working, idle) changes every few seconds, so it moved to the app's detail pane, and "attached" appears only when the supervisor actually reports a terminal; an unreadable status no longer reads as attached. `pier ls --json` keeps its raw states. A claim used to list its session as parked while resuming the stopped pool member. The claim now clears the ready marker at its commit point and MarkReady sets it once the session is usable, so it reads starting in between, like a fresh create; a claim that died midway reads parked again after 15 minutes. Background refreshes no longer flash the spinner.
…ches
The public-IP lookup that gates direct ssh depended on one service; where a
network filters it (secure gateways and VPNs do), every command waited out
its timeout and fell back to the tunnel. Three services are now raced with
a two-second cap. The list call also returns each instance's address and
security group, so the probes that follow it skip their own describe call,
and the app shows the list as soon as it lands and fills in each session's
status after.
Attaching from the app stays on screen ("connecting…") until the VM
answers, then hands over the terminal; failures show in the app. A session
whose ssh key isn't on this machine fails at once with a clear error
instead of ssh retrying for minutes.
sshd never timed out a dead connection, so a dropped attach left a phantom
tmux client: the session read as attached and could never park. Sessions
now drop dead connections after about a minute.
The new-session input is a plain text field.
Contributor
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
One setting in a new Appearance group: teal (the default, the terminal's own cyan), navy, violet, emerald, orange, crimson, pink, amber or graphite. It recolors the app's borders, tabs, keys and highlights at once and the CLI's accents too. Dark accents draw the active tab's text in white.
Contributor
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
Attaching hands the terminal to ssh, and until the session drew itself the user's own shell showed through — it read as if pier had quit. The handover now opens a blank screen reading "connecting to <session>…" that tmux draws over. The CLI restores its screen after the detach; the app redraws itself. The attach's exit status is unchanged.
Contributor
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
Contributor
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
A headless session can't finish a browser login: the login page has nowhere to open, and the provider's redirect to localhost reaches the laptop, where nothing listens. While someone is attached, both now work. The session's xdg-open and $BROWSER hand URLs to the supervisor, which sends them over a socket the attach forwards, and they open in the laptop's browser (http and https only). A side connection mirrors the ports the session listens on to the same localhost ports, so callbacks and dev servers are reachable. Any agent or CLI's browser login — an MCP server's OAuth, `gh auth login` — works from inside the session. The pool's generation now includes the in-VM supervisor: a claim doesn't reinstall it, so a pooled session filled by an older pier would carry the older VM-side behavior into the session. BREAKING CHANGE: `pier mcp login` is removed; log in from inside the session instead.
Contributor
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
Contributor
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
Contributor
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A session's startup was dominated by the repo's own setup, which the toolchain-only image couldn't cache, and every session repeated it. Parking discarded everything that was running, so waking a session meant rebuilding the tmux layout and restarting services by hand. And a headless session couldn't finish a browser login.
Startup
pier bakeprebuilds the repo: it runs.pier/setup.shon a checkout, scrubs every file pier pushed into the instance (credentials, env files, logs, containers), and images the result. Sessions from the image fetch only what changed and run setup on warm caches.Parking
Connecting
$BROWSER) open on your laptop, and ports it listens on are reachable at the same localhost port. So any in-session browser login works — an MCP server's OAuth, a CLI's web login — for every agent.Using it
.pierscripts changed since the bake); pier never rebakes on its own.pier setupshows every default with its cost for confirmation and offers to bake the current repo.+/-size,ffill,xdrain) or withpier pool,pier pool set <n>,pier pool fillandpier pool drain [repo].Structure
pkg/pierholds every capability behind one client used by the CLI and the app, and later a Mac app. It never prints, exits or reads stdin, and reports progress as typed events.Breaking changes
pier mcp loginis removed; log in from inside the session.pier skills→pier setup --skills.pier pool's subcommands areset,fillanddrain.pier lsshows the steady states (pier ls --jsonkeeps the detailed ones).