docs: personalized dev environment (dotfiles + persistent home)
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
# Personalized dev environment (dotfiles + persistent home)
|
||||
|
||||
Makes the workspace terminal feel like the user's own machine: a Fedora image
|
||||
preloaded with QoL CLI tooling, a persistent per-user home, and user dotfiles.
|
||||
|
||||
## The model
|
||||
|
||||
- **Persistent per-user home.** Each user gets a home directory on the worker
|
||||
host at `${SPOON_AGENT_WORKDIR}/homes/{username}`, bind-mounted into every
|
||||
job/terminal container at `/home/{username}` (`HOME`). It survives across
|
||||
sessions, so dotfiles, installed tools, nvim plugins, and shell history persist.
|
||||
`username` is derived from the user's profile first name (sanitized).
|
||||
- **Threads as folders.** Each thread's checkout lives at
|
||||
`~/Code/{spoon}/{branch}` inside that home, so every thread shows up as a
|
||||
folder in one home. The agent (`codex --cd …`) and the terminal both open there.
|
||||
- **Neutral defaults (everyone).** The Fedora job image
|
||||
(`docker/agent-job.Dockerfile`) ships zoxide, eza, bat, fzf, fd, ripgrep, gh,
|
||||
gum, neovim, tmux, oh-my-posh, etc., plus system-wide defaults that work even
|
||||
with an empty home: `/etc/profile.d/spoon.sh` (tool init + aliases),
|
||||
`/etc/tmux.conf` (login-shell panes), `/etc/spoon/omp.json` (prompt theme).
|
||||
- **User dotfiles (per-user).** Configured in **Settings → Dotfiles**, applied on
|
||||
top of the neutral defaults.
|
||||
|
||||
## Settings → Dotfiles
|
||||
|
||||
A mini file-browser workspace rooted at `home/{firstName}`:
|
||||
|
||||
- **Editable overlay tree** — drag in files/folders (or use Upload folder/files),
|
||||
edit them in the Monaco editor, add/delete. Files are placed **relative to
|
||||
`$HOME`** (`.bashrc` → `~/.bashrc`, `.config/nvim/…` → `~/.config/nvim/…`).
|
||||
Stored encrypted at rest (`userDotfiles`, AES-256-GCM via `secretCrypto`).
|
||||
- **Dotfiles repo (optional)** — a **public** git repo URL + optional ref + a
|
||||
setup script path. On start the container clones it to `~/.dotfiles` and runs
|
||||
`bash ~/.dotfiles/<setup>` (e.g. a bootstrap that symlinks configs, like the
|
||||
user's Panama `install`).
|
||||
- **Precedence (hybrid):** repo clone + setup runs first; then the editable
|
||||
overlay is written on top — **overlay wins**.
|
||||
|
||||
Secrets: dotfiles are encrypted, but real API keys/tokens belong in a Spoon's
|
||||
**Secrets** feature (injected as env vars), not in dotfiles. The UI nudges this.
|
||||
|
||||
## Materialization (worker)
|
||||
|
||||
`apps/agent-worker/src/user-environment.ts`:
|
||||
|
||||
1. `fetchUserEnvironment(jobId)` — a worker-token Convex action
|
||||
(`userDotfilesNode.getEnvironmentForJob`) returns the owner's decrypted
|
||||
dotfiles + repo/setup config.
|
||||
2. `materializeUserHome` — ensures `~/.bash_profile` (so login shells source
|
||||
`~/.bashrc` in a mounted home with no `/etc/skel`); clones the repo + runs the
|
||||
setup command **inside the job image** (so the user's tools/paths apply), only
|
||||
when the config hash changes (`~/.spoon/env-hash`); writes the overlay files.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Variable | Default | Notes |
|
||||
| ------------------------------------------ | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
|
||||
| `SPOON_AGENT_WORKDIR` | `.local/agent-work` (dev) / `/var/lib/spoon-agent/work` (prod) | Per-user homes live under `homes/{username}`; reuses the existing host-path translation. |
|
||||
| `SPOON_ENCRYPTION_KEY` / `INSTANCE_SECRET` | — | Already required; encrypts dotfiles like other secrets. |
|
||||
|
||||
No new required env. The home is a host directory under the existing workdir, so
|
||||
the prod bind-mount + `SPOON_AGENT_HOST_WORKDIR` translation already covers it.
|
||||
|
||||
## Notes / limits (Phase 1)
|
||||
|
||||
- **Repo auth:** public repos only. Private/self-hosted (e.g. Gitea) dotfiles
|
||||
repos are a follow-up (store a token/deploy key).
|
||||
- **Binary files:** the overlay is text-first.
|
||||
- **Cleanup:** `~/Code/{spoon}/{branch}` checkouts persist (threads as folders);
|
||||
a per-thread "delete checkout" action is a follow-up.
|
||||
- **Concurrency:** jobs share one home; fine at the default
|
||||
`SPOON_AGENT_MAX_CONCURRENT_JOBS=1`.
|
||||
|
||||
## Phase 2 north star
|
||||
|
||||
A single long-running per-user container that every thread `exec`s into (agent
|
||||
via `docker exec`, not `docker run --rm`). The per-user home + `~/Code/{spoon}/
|
||||
{branch}` layout built here is its foundation.
|
||||
Reference in New Issue
Block a user