con un clic
upstream-pr
Upstream elyxlz/vesta GitHub ops: branches, PRs, issues, CI, API.
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Menú
Upstream elyxlz/vesta GitHub ops: branches, PRs, issues, CI, API.
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Basado en la clasificación ocupacional SOC
Use for any Microsoft account, personal or work (Outlook.com, Hotmail, Live, Microsoft 365); preferred over email-client for Microsoft accounts. Graph-based mail (read/send/reply/forward, drafts, flag/categorize, move/archive, folders, attachments, block senders), calendar and meetings, Microsoft Teams (chats, channels, presence), and new-mail/Teams notifications. Requires daemon.
Browse, navigate, click, fill forms, screenshot, or scrape web pages with a stealth (Camoufox) browser.
Design judgment and UI copy for building Vesta dashboard widgets that feel considered rather than templated, within the fixed design system.
Use before building or modifying the user's dashboard: widgets, pages, layouts, custom UI. Understand what the user wants, design it, write a spec, then dispatch the dashboard-builder to build it.
Use when someone who doesn't have their own vesta asks what vesta is, how to get one, or hints they want in. Vesta is invite-only: you gatekeep and build desire through scarcity, draw out what they want, then sell vesta as indispensable to their goals and set them up end-to-end in chat. Not for the owner, who already has one.
Talk to vestad, the host daemon that runs this container. Register a background service to get a port, build public URLs, update vestad to the latest release, check its version, and read gateway logs. Use when a skill needs an inbound port or a shareable link, when the user asks to update Vesta, or when debugging gateway/container issues.
| name | upstream-pr |
| description | Upstream elyxlz/vesta GitHub ops: branches, PRs, issues, CI, API. |
Push contributions back to elyxlz/vesta. Authentication is handled by the vesta-upstream GitHub App, no personal tokens needed.
uv tool install --editable ~/agent/skills/upstream-pr/cli
Don't wait to stumble on things worth upstreaming: sweep for them. Your workspace (~) is a git repo whose stock baseline is the tag agent-vX.Y.Z matching the version you run. Diffing your branch against that tag surfaces everything you've changed or added on top of stock, i.e. the full contribution surface, in one command:
VER=$(grep '^version = ' ~/agent/core/pyproject.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
git -C ~ diff --stat "agent-v$VER"..HEAD -- agent/ ':(exclude)agent/core/**'
Walk the list and, for each changed/added file, decide with gate 1 below: generalizable → file it; user-specific → leave it local. Common finds: a hook, script, or SKILL.md improvement built for one task that any instance would want.
Go WITHIN each file, not just file-by-file. The --stat view tempts you to sort at the whole-file level ("MEMORY.md is personal → skip", "a new skill → file"), but a file that is mostly user-specific almost always carries general improvements buried inside it: a restart SKILL.md that mixes a user-specific service list (local) with a hard-won "a migration prompt is a boot turn, restore daemons first" note (general); a skill doc where a mechanism is general but the specific names/addresses are personal. So for every changed file, git -C ~ diff "agent-v$VER"..HEAD -- <file> and read the actual hunks: split each into the general part (the rule, the mechanism, the fix) and the user-specific part (names, addresses, paths, one person's texting quirks). Upstream the general part with the personal part stripped or genericized; leave only the truly personal remainder local. The unit of contribution is the improvement, not the file.
Two gotchas learned the hard way:
agent-vX.Y.Z tag, NOT upstream/master. Vesta serves the workspace as a subset of the full monorepo (no core/, tests/, frontend), so a raw diff against upstream/master is polluted with thousands of phantom "deletions" for files that aren't in your workspace at all. The tag is your exact stock baseline, so its diff is purely your real changes.Four gates before opening a worktree.
0. Does it already exist? (grep FIRST, in the natural layer.) Before building or upstreaming any mechanism, grep -rn the codebase for an existing implementation, and look in the layer where it would naturally live, not just one spot. It's easy to check only one directory (e.g. a hooks/ dir), conclude "not upstream yet", and file a redundant PR that duplicates a check already wired into a channel CLI or core. Duplicated logic is a smell that the solution isn't the right one. So: search by the FEATURE name across all skills + core, not by where you assume it lives; if it exists, improve that one, don't add a second.
1. Is it worth filing? The rule for everything below: generalizable goes upstream, user-specific stays local. Everything is upstreamable unless it's personal information or super niche to one user; if a change would help any vesta instance, it belongs upstream. Concretely:
personality SKILL.md shared rules, the presets/*.md preset files, the bubble_lint hook). These ship with every vesta, so a sharpened rule that isn't glued to one user's specifics benefits everyone.2. Issue, PR, or both?
fixes #N / closes #N / resolves #N) on its own line. GitHub only auto-closes the linked issue on merge when that keyword is in the PR body, so without it the issue stays open after the PR merges and someone has to close it by hand. Put it in the body, NOT the commit message (per CLAUDE.md, commits carry no closing keywords). upstream-pr --body "...fixes #N" is enough.3. Strip personal information. Upstream is public, so the user must not be identifiable: never file personal config, their own memory content, credentials, or user-specific customizations (a rule that names the user or their contacts, a preset drifted to one person's texting quirks). Describe the pattern in general terms ("agent claimed inability to access calendar when google skill was installed"), not the specific instance ("user asked about tuesday's meeting with..."). When in doubt, leave it out.
When you add functionality to a skill that already ships a CLI (cli/), fold it in as a subcommand of that CLI, reusing its shared auth/client/helpers; do not drop a standalone script beside it. One entry point per skill: a loose script re-implements auth, escapes the skill's tests, and rots. Ship the subcommand with a test under cli/tests/ and document it in SKILL.md alongside the others.
Every PR and every issue must carry the agent name and vesta version, so maintainers know which agent on which version hit the bug or proposed the change.
$AGENT_NAME~/agent/core/pyproject.tomlupstream-pr automatically appends Submitted by **<name>** on <version> to PR bodies. For issues, append the same footer to the body yourself:
---
Submitted by **$AGENT_NAME** on vesta v<version>
The home ~ workspace ignores everything outside agent/, and local commits diverge from upstream; never branch from local HEAD. Always use a clean worktree off origin/master.
Create the worktree:
git -C ~ fetch origin
git -C ~ worktree add /tmp/vesta-pr -b feature/<name> origin/master
File the linked issue first (if doing PR + issue), so the PR can reference it. See "Filing an issue" below.
Apply changes to /tmp/vesta-pr.
Commit and submit:
cd /tmp/vesta-pr
git add <files> && git commit -m "<description>"
upstream-pr --title "..." --body "..."
Clean up: git -C ~ worktree remove /tmp/vesta-pr
Wait for CI to pass. Get a token with upstream-pr --token-only, then poll the check-runs endpoint. If a check fails: diagnose, fix, commit to the same branch, push, the PR updates automatically. The lockfile check requires uv lock in ~/agent if Python deps changed.
Only report a PR as done once every CI check is green.
Get a token with upstream-pr --token-only, then POST to the GitHub Issues API. The title should name the pattern, not the specific instance. The body must include the attribution footer (see "Attribution").
# Create a PR (auto branch, base=master)
upstream-pr --title "fix: ..." --body "..."
# Custom branch and base
upstream-pr --title "..." --branch my-branch --base master
# Short-lived GitHub API token (for issues, check-runs, PR status)
upstream-pr --token-only
Each skill CLI is its own uv project, so run its tests from its own directory: cd ~/agent/skills/<name>/cli && uv run pytest. uv builds a local .venv there and leaves the engine venv at ~/agent/.venv alone.
Before pushing changed .py, format from ~/agent so the pinned ruff and config match CI's guards ruff pass: cd ~/agent && ruff format <path> && ruff check <path>. Plain ruff from that dir is the engine venv's pinned ruff (its bin leads your PATH), never uvx ruff or another cwd: those ignore the lock (agent/core/uv.lock) and config (agent/ruff.toml) and can fail CI's --check on otherwise-correct code.
Before pushing changed prompt or skill .md, check for em dashes (U+2014) and en dashes (U+2013): grep -rnP '\x{2014}|\x{2013}' <paths> must be empty. CI's test_no_em_or_en_dashes_in_prompt_and_skill_files (agent-tests) fails the build on either character in those files; use commas, colons, or hyphens instead. Watch this especially when a subagent did the editing: instruct it up front, since models reach for those dashes by default. (This note avoids the literal characters for the same reason.)