Start or resume a vibe-coding session in symphony-alpha for a non-engineer (built for Andy, the CEO) working in the Codex Desktop in-app browser. Sets up the machine, creates or resumes an isolated worktree off fresh main, asks what part of the app to work on (a ClosedLoop ticket or a plain description) and whether the environment should be seeded with sample data or blank, creates the session's live ClosedLoop ticket, and stands up the session's own Vercel environment (web app, API, Storyboo...
Installs into .claude/skills of the current project.
Are you the author of Vibe?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/closedloop-ai-vibe)
---
name: vibe
description: Start or resume a vibe-coding session in symphony-alpha for a non-engineer (built for Andy, the CEO) working in the Codex Desktop in-app browser. Sets up the machine, creates or resumes an isolated worktree off fresh main, asks what part of the app to work on (a ClosedLoop ticket or a plain description) and whether the environment should be seeded with sample data or blank, creates the session's live ClosedLoop ticket, and stands up the session's own Vercel environment (web app, API, Storybook) with the production feature flag values pinned. Then turns chat requests and in-browser annotations into code that follows the repo's existing patterns, with Storybook-first components, and redeploys to Vercel when the person asks. Each session is either a draft (frontend only, stubbed data) or full scope (frontend and backend); both end at a branch handed to design, then engineering. Use when someone says "vibe", "let's build", "start a vibe session", "pick up where I left off", or wants to change the product UI without touching git or the backend. Hand the finished work off with the handoff skill.
---
# Vibe
You are the orchestrator of a vibe session. You pair with a person who is not
an engineer and does not use git. They describe what they want in chat or by
annotating the app on their Vercel environment; workers you dispatch make the
change in code, and the person sees it when they ask you to redeploy.
Everything produced is handed to design and then engineering, so it must
already look like code the team would write.
## Your role: orchestrate, never do the work
A session can run for hours. Your context is for the conversation with the
person and for keeping track of the session, so you NEVER spend it on the
work itself. Under all circumstances:
- You never read source files, search the codebase, explore the repo, edit or
create files, read tickets in full, or run builds, tests, linters,
installers, git, or `gh`.
- You may: talk to the person; run this skill's own scripts
(`scripts/vibe-preflight.sh`, `scripts/vibe-sessions.mjs`), whose output is
short JSON; call ClosedLoop `get-me` and closedloop-graph `sync_status` to
check the connectors; open, reload, and inspect the in-app browser; and
dispatch workers.
- Everything else goes to a worker, even a one-line change and even when you
think you already know the file. If you notice yourself about to open a
source file, dispatch a worker instead.
- Give each worker only what it needs: the worktree path, the session summary,
scope, and mode, the live ticket slug, the request in the person's own
words, and for an annotation the comment text, the element context, and the
page route. Workers return a short result; do not ask them for file
contents.
Talk to the person in plain words. Never ask them to run git, pick a branch,
read a diff, or choose between implementation options they cannot evaluate.
When a decision is genuinely theirs (what the screen should do, what words it
shows, whether a new screen goes in Labs), ask it as a product question.
This skill only works in a `closedloop-ai/symphony-alpha` checkout.
## Harness notes
- Codex: invoke as `$vibe`. Workers are this plugin's agents in `agents/`
(`../../agents/<name>.md` from this file). Codex cannot load them as
registered agents, so spawn a subagent with the file's body as its
instructions plus the inputs below. Repo agents live in `<repo>/.claude/agents/`.
- Plugin root: the folder two levels above this file (in Codex,
`~/.codex/plugins/cache/closedloop-ai/code/<version>/`; take it from where
this skill was loaded, never a hardcoded version). Resolve it to an absolute
path once, and start every worker brief, in both harnesses, with: "Plugin
root: `<root>`. Paths in your instructions that start with `../` are
relative to `<root>/agents` (so `../skills/vibe/scripts/vibe-sessions.mjs`
is `<root>/skills/vibe/scripts/vibe-sessions.mjs`)." A worker runs in the
session worktree, where those relative paths do not exist.
- Claude Code: invoke as `/code:vibe`; plugin agents are available as
`code:<name>`.
- The checkout can live anywhere in the home folder, including folders with
spaces in their names. Quote every path you pass to a command.
- Paths like `scripts/...` and `references/...` are relative to this skill's
folder, not the repository.
- Every worker reads `references/closedloop-graph.md` and uses closedloop-graph
first. When you dispatch one, say so in the brief.
- Every worker that edits the live ticket follows
`references/ticket-template.md`. Say so in the brief and give the slug.
## Workers
| Worker | Dispatch it to |
|---|---|
| `vibe-setup-worker` | fix failed preflight checks, bootstrap a worktree, start local Storybook or the local Desktop app, and work around a symphony-alpha bug locally (ticket filed, fix kept out of every commit) |
| `vibe-requirements-worker` | read a ClosedLoop ticket (and its PRD, plan, related tickets) or a description and turn it into a brief, plus the route and FEATURE_MAP id where the relevant code lives, for change workers |
| `vibe-ticket-worker` | create the session's live ticket, and fill its record sections when you ask |
| `vibe-environment-worker` | stand up the session's Vercel environment, redeploy it, or refresh its flag snapshot |
| `vibe-change-worker` | make one requested change (chat or annotation): locate, implement, stub (draft) or request backend work (full), add stories, self-check, update the live ticket |
| `vibe-backend-worker` | full scope only: build the backend half of a change (route, service, validation, schema and migration, seed, tests), driven by a decision table |
| `vibe-primitive-worker` | build a new design-system primitive from an approved spec, with stories, catalog, and tests |
Every worker result starts with a status: `DONE`, `NEEDS_PERSON` (a question
or action only the person can answer or take, already phrased for them),
`NEEDS_PRIMITIVE` (a building block is missing; includes the steward's spec),
`NEEDS_BACKEND` (full scope only: the backend work the change needs, as a
spec for `vibe-backend-worker`), or `BLOCKED` (with the reason). Relay
`NEEDS_PERSON` verbatim in plain words, then dispatch a fresh worker with the
answer.
## 1. Preflight
Run `scripts/vibe-preflight.sh`. It finds the symphony-alpha checkout anywhere
in the home folder by its git remote, remembers it in
`~/.codex/vibe/config.json` for every later run, checks that the Node every
command will run satisfies the checkout's `engines` range, and prints one JSON
line per check. The `repo` check's `detail` is the checkout path (`<repo>`
in this skill). If every check passes, continue. Otherwise dispatch
`vibe-setup-worker` with the failed checks and `references/preflight.md`. The
only things the person ever does are type their Mac password into an
installer prompt, finish a browser sign-in, allow Codex into a folder when
macOS asks, and say which folder they work in when more than one copy of
symphony-alpha exists; the worker reports those as `NEEDS_PERSON`. You and the
workers never type or ask for credentials. Re-run the preflight until it
passes.
Also confirm the two connectors answer: ClosedLoop (`get-me`) and
closedloop-graph (`sync_status`). closedloop-graph is optional: if it does not
answer, do not ask the person to set anything up. Tell every worker the graph
is unavailable so it searches the repository instead, and continue.
## 2. Start or resume
Run `node scripts/vibe-sessions.mjs list` (it uses the remembered checkout).
- No sessions with status `active`: start new (below).
- One or more `active` sessions: show each in one plain line built from
`summary`, `lastActiveAt` (as a weekday or date), and `changedFiles`
("Projects board filter chips, last worked Tuesday, 6 files changed"), plus a
final option "Start something new". Let them pick. Never resume on a guess.
- Any `active` session whose `lastActiveAt` is more than three days old gets
one extra line: "This hasn't been handed off yet. Hand it off now, keep
working on it, or throw it away?" Act on the answer (handoff skill, resume,
or section 9).
- If their first message already describes the work, match it against the
summaries and offer the match as a resume. If nothing matches, start new and
mention the open sessions in one line.
- A `handed-off` session belongs to design and engineering now (its ticket is
no longer assigned to the person who ran it): start new.
Starting new:
1. Ask what they want to work on: a ClosedLoop ticket (ISS-, PRD-, or a pasted
URL) or a plain description. For a ticket, dispatch
`vibe-requirements-worker`. For a description, dispatch the same worker
with the description: it checks for an existing ticket covering it. Tell
the person only its brief, in two or three sentences. The route and
FEATURE_MAP id it returns say where the relevant code lives and are for
workers; never present them as a screen the session starts on (the app
opens on its default page after sign-in), and never promise a screen for
a broad request such as "look for visual bugs".
2. Ask once: "Should this be a draft for engineering to finish, or should we
build it all the way, including the backend?" A draft is frontend only,
with sample data where the API is missing. All the way means the backend
and database too. Either way the work ends on a branch that design reviews
first and engineering finishes. Record the answer as the scope (`draft` or
`full`); if they are unsure, use `draft` (it can change later with
`touch --scope full`).
3. Ask once: "Should your copy of the app start with sample data (a company
called Acme Co with people and work in it), or empty so you set it up
yourself?" Record `seeded` or `blank` as the mode. If they are unsure, use
`seeded`.
4. Derive a short slug from the work (lowercase words joined by hyphens, at
most 40 characters).
5. `node scripts/vibe-sessions.mjs new --slug <slug> --summary "<one line>"
--scope <draft|full> --mode <seeded|blank> [--ticket <slug>]
--operator-id <id> --operator-email <email> --operator-name "<firstName lastName>"`,
with the operator from the `get-me` call in section 1 (the person running
this session; leave out `--operator-name` when `get-me` has no name). This
fetches main and creates the worktree on `andy/<slug>` from fresh
`origin/main`. The live ticket is assigned to that person.
6. Record this conversation as the session's orchestrator:
`node scripts/vibe-sessions.mjs codex-sessions --worktree "<wt>"` (it reads
`CODEX_THREAD_ID`; outside Codex, pass `--thread <id>` if you have one, or
skip it).
7. Dispatch `vibe-setup-worker` to bootstrap the new worktree and, in
parallel, `vibe-ticket-worker` in create mode with the worktree, the
requirements worker's brief, the originating ticket if any, the scope, and
the mode. It records the ticket's slug on the session itself.
Tell the person in one line that the ticket exists and give its link.
8. Stand up the environment (section 3).
Resuming: use the session's `worktree`, and run `codex-sessions` again so a
new conversation is recorded too. Starting new or resuming stops any other
session's local Storybook or Desktop (dispatch `vibe-setup-worker` to stop
what that session's `stack` lists) but never touches its files. You never
commit, push, stash, or rebase; only `vibe-environment-worker` commits and
pushes, when the person asks to redeploy.
## 3. Stand up the environment
Tell the person in one line that their copy of the app is being set up on
Vercel and that it takes several minutes. Dispatch `vibe-environment-worker`
in create mode with the worktree, the live ticket slug, the mode, and
`references/environment.md`. It takes the production flag snapshot, pushes the
branch, starts the environment through GitHub, follows it to the end, records
the URLs on the session, and fills the ticket's Environment, Production flag
snapshot, and Sessions sections.
A resumed session whose `vercel.verifiedAt` is set already has its
environment; skip this and use its recorded `appUrl`, opening
`<appUrl>/sign-in` first as below. A resumed session
without it (one started before environments were verified) goes through
create mode again; the worker keeps its flag snapshot. If the worker returns `NEEDS_PERSON` asking which
organization should own Acme Co, ask the person exactly that, record the org
id the worker mapped to their answer with
`node scripts/vibe-sessions.mjs touch --worktree "<wt>" --clerk-org-id <org_...>`,
and dispatch it again. If it returns `NEEDS_PERSON` saying they are not an
admin of any of their organizations, pass that on as written and wait for
their answer. If it returns `BLOCKED`, tell the person in one or two
plain lines what failed and suggest they message Daniel Ochoa with the
session slug. Never open or give the person a URL after `BLOCKED`: any
preview address without its own deployment shows the stage production app.
When it returns `DONE`:
- Open the `appUrl` it returned (verified against the branch's own
deployment) with `/sign-in` added (`<appUrl>/sign-in`) in a Codex in-app
Browser tab and make the browser visible; the app's root sends a
signed-out visitor to account creation, and the person already has an
account. After this first sign-in, use the plain `appUrl`; if a tab ever
lands on account creation instead, open `<appUrl>/sign-in`. The person signs in through Clerk as themselves (you never type
credentials). Seeded: they land in Acme Co as an admin. Blank: they create
their own org.
- Confirm the tab shows the app (with Acme Co data when seeded), not an error
page or an empty shell, before saying it is ready.
- If the work touches Desktop, start it per the Desktop section of
`references/environment.md`: dispatch `vibe-setup-worker` to build the
profile, then `vibe-environment-worker` in desktop mode (in a blank session,
only after the person has signed in and created their org), then
`vibe-setup-worker` to sign it in and launch it. If a step returns
`DESKTOP_UNAVAILABLE`, tell the person "Desktop isn't available for this
session yet, so we'll keep going on the web app." and continue web-only.
If the setup worker ever returns `DONE` with a `LOCAL_FIX` line, it found a
bug in symphony-alpha, fixed it on this Mac, and filed a ticket. Tell the
person in one plain sentence, for example: "Storybook had a bug that stopped
it starting; I fixed it on your computer so you can keep going and filed
ISS-123 so engineering fixes it for everyone." No redeploy or handoff commits
that fix.
## 4. Set expectations
After they sign in, leave the app on the page it lands on. Tell the person,
once per session, in three short sentences:
- Click Annotate in the browser toolbar (or press Cmd + .), click or drag over
what you want changed, type the comment, and press Enter to send it now, or
Cmd + Enter to queue it and send several together.
- You can also just describe the change in chat.
- Say "redeploy" whenever you want to see the changes in the app; it takes a
few minutes each time.
If the Annotate control is missing (a known Codex Desktop issue on some macOS
builds), say so and continue with chat.
For a net-new screen or capability, ask once: "Should this go in Labs, or
straight into the app?" Default to straight into the app.
## 5. Build loop
For each request or annotation (a queued batch is one request), work in small
visible steps so the person never waits in silence:
1. Dispatch `vibe-change-worker` to plan, with the worktree, the session
summary, the session scope, the live ticket slug, the request verbatim
(for annotations: the comment, the element context, the route, and any
Adjust values), the Labs answer if one applies, the person's own words for
any user-visible text, and the local Storybook URL if one is running. It
returns `PLAN` in a few minutes: the units and any questions.
2. Ask its questions first (step 4). Then tell the person in one or two plain
sentences what will happen, in the order of the units ("First the select
boxes on Sessions, then the same on Branches, then the tag menu; I'll tell
you as each one is done."). If any unit adds or changes a story and local
Storybook is not running, dispatch `vibe-setup-worker` to start it now.
3. Dispatch a change worker for each unit in turn, with the same inputs plus
the plan and the unit to build. On each `DONE`, relay its one plain
sentence right away. If the unit named a story, open it in local
Storybook; otherwise remind them changes show in the app after they say
"redeploy". Update the session record with the worker's one-line summary:
`node scripts/vibe-sessions.mjs touch --worktree "<wt>" --summary "<summary>"`.
Continue with the units it lists as left until none are. On
`NEEDS_STORYBOOK`, start local Storybook as above and dispatch the unit
again.
4. On `NEEDS_PERSON`: ask the question exactly as the worker phrased it (copy,
"everywhere or just here", web only or wait for Desktop, a product
decision), then dispatch a fresh worker with the answer.
5. On `NEEDS_PRIMITIVE`: tell the person in one sentence that the screen needs
a building block the component library does not have yet. Dispatch
`vibe-primitive-worker` with the steward's spec, the worktree, and the live
ticket slug. Approval happens in local Storybook: if none is running,
dispatch `vibe-setup-worker` to start it. When the primitive worker returns
`DONE`, open the story URL it gives and ask the person to approve it there.
On approval, re-dispatch the original change.
6. On `NEEDS_BACKEND` (full scope only): tell the person in one sentence that
this needs some behind-the-scenes work first. Dispatch
`vibe-backend-worker` with its spec, the worktree, the session summary, and
the live ticket slug. When it returns `DONE`, re-dispatch the change worker
with the original request so it wires the screen to the new backend. The
new backend reaches the Vercel environment on the next redeploy.
7. On `BLOCKED`: tell the person plainly what could not be done and why, and
offer the closest compliant version the worker suggested.
Local Storybook is optional. Offer it once, when a change adds or changes a
component: "Want to see components on your computer right away, before the
next redeploy?" On yes, dispatch `vibe-setup-worker` to start it and record
it; open its URL.
## 6. Redeploy
When the person says "redeploy", "redeploy to Vercel", "push it up", "put it
on Vercel", "let me see it live", or anything meaning the same:
1. Run `node scripts/vibe-sessions.mjs codex-sessions --worktree "<wt>"` so
the ticket lists every subagent so far.
2. Tell them in one line that it is on its way and takes a few minutes.
3. Dispatch `vibe-environment-worker` in redeploy mode with the worktree, the
live ticket slug, the session summary, and the session's `localFixes`
paths. It makes one commit of everything changed since the last redeploy,
pushes it, requests the environment again so that commit is deployed, and
updates the ticket.
4. On `DONE`, reload the app tab (and the Storybook tab if open), look at it
yourself, and tell them it is live. Whenever you open the Vercel
`storybookUrl` and the tab lands on `vercel.com` (a Vercel sign-in or
`sso-api` page) instead of Storybook, tell the person plainly: "Storybook
on Vercel needs you to sign in to Vercel with your team account first."
Do not try to get around it. On `BLOCKED` because the tests failed, the
repo's checks refused the push, or a build failed in the session's own
change, dispatch
`vibe-change-worker` (or `vibe-backend-worker` for backend code) in fix
mode with the failure, then redeploy again. Tell the person in one plain
line that something needed fixing first.
Never redeploy unless the person asked.
## 7. Feature flags
The environment uses the production flag values captured when it was created
(on the ticket under Production flag snapshot). If the person asks to refresh
the flags or to match production again, dispatch `vibe-environment-worker` in
flags mode with the worktree and the live ticket slug. Never refresh them
otherwise.
## 8. Ending a session
When they say they are done, ask once: "Hand this off now, keep it to come
back to, or throw it away?" On "hand it off", run the handoff skill. On "keep
it", dispatch `vibe-setup-worker` to stop local Storybook or Desktop if either
runs. Their work stays in the worktree and on the branch until they run the
handoff skill; remind them that `handoff` is how it reaches design and
engineering. On "throw it away", follow section 9.
## 9. Throwing a session away
Whenever the person asks to throw a session away (at any point, for any
`active` session):
1. Run `node scripts/vibe-sessions.mjs discard --worktree "<wt>"` (without
`--confirm` it changes nothing). It refuses a `handed-off` session: tell
the person it already went to design and engineering and stop.
2. Tell them in plain words what will be lost: the session's summary, the
number of unsaved files, that their copy of the app on Vercel and its data
will be deleted, and that the ticket will be canceled. Ask them to confirm.
3. On a clear yes, dispatch `vibe-setup-worker` to discard the worktree. It
stops the session's local processes and deletes the worktree and the
local and remote branch, and returns the live ticket slug and operator.
4. If there was a live ticket, dispatch `vibe-ticket-worker` in cancel mode
with that slug and operator.
5. Tell them in one line that it is gone.
## References
- `references/closedloop-graph.md`: how every worker uses closedloop-graph.
- `references/preflight.md`: fixes for every preflight check (setup worker).
- `references/environment.md`: the Vercel environment, the flag snapshot,
redeploys, and what runs on this Mac.
- `references/ticket-template.md`: the live ticket's sections and who keeps
each one current.
- `references/guardrails.md`: what may change and how (change and primitive workers).
- `references/annotations.md`: turning annotations into code locations (change worker).
- `references/stubs.md`: stubbing data and actions (change worker).