# How a DemoPrep change gets to test *2026-10-22. Agreed with boone on 10-20 and 10-21. Code: `demoprep_app/tracker/`, `scripts/pipeline_run.py`, `scripts/agent_worker.sh`, the tracker tools in `mcp_server.py`. The agent that fronts it: `docs/agentspot_task_manager_agent.md`.* ## The shape ``` branch off develop ──> pull request into develop ──> approved ──> pickup run (4x a day) │ merge into develop, suite, push origin, push the test Space when it is idle │ boone promotes test ──> prod by hand ``` **One integration branch: `develop` on origin.** The test Space (`hf-mcp-test`, test-mcp) always runs `develop`. Only the pickup run moves it. Production is unchanged: `prod/mcp` is pushed to `hf-mcp` by boone, fast-forward, in prose. **Every change is a new branch off `develop`** with a name that says what it does, the task key first when there is one: | Kind | Example | |---|---| | fix | `fix/t42-yodeck-grade-handles-null-rates` | | feat | `feat/tracker-tasks-beside-pull-requests` | | docs, test, chore | `docs/t51-development-process` | | the agent's | `agent/t42-yodeck-grade-handles-null-rates` (the worker names these) | A pull request into `develop` is the only way back. Put the task key (`T-42`) in the title or body if the branch name does not carry it; the tracker links the PR to its task from either. ## Approval | Who opened it | What happens | |---|---| | Mike (`boone10`) or Jack (`jackrayner-ts`), on any branch except `agent/` | approved on arrival (`auto`) | | anyone else, or any `agent/` branch | waits for Mike or Jack: a GitHub review, or "approve #57" to the Task Manager agent, which calls `approve_pull_request` | | an approver requests changes | held (`changes_requested`) until their later review approves | To hold your own PR back, make it a draft. The policy lives in `tracker_people.can_approve` / `auto_merge`, derived by the sync in `demoprep_app/tracker/github_sync.py`. ## The pickup run `scripts/pipeline_run.py`, on boone's Mac under launchd at **7:30, 11:30, 15:30 and 19:30 Eastern** (`scripts/launchd/com.demoprep.pipeline.plist`). Each run: 1. On the 7:30 run, turns recent build warnings (`demo_findings`) into tasks for the agent, one per finding code (`demoprep_app/tracker/findings.py`). 2. Reads the queue: open PRs that are approved, not drafts, targeting `develop`, not red, not conflicting. The rest are listed with the reason they are held. 3. In its own worktree (`pipeline/` in the repo, gitignored), merges each ready PR into `develop`, oldest first, `--no-ff`. A conflict skips that PR and notes its task. 4. Runs the unit suite (`pytest tests --noconftest`). A failure that is not in `scripts/pipeline_known_failures.txt` means no push and a p1 task for the agent. 5. Pushes `develop` to origin. 6. Waits until the test Space has been idle for three minutes (no active build, no build finished in the last three minutes: a push restarts the Space and wipes results SEs are still polling), pushes `develop` to `hf-mcp-test` main, waits for `ping` to report the pushed sha, records a `deployments` row, and notes "on test-mcp as " on each merged PR's task. If the Space stays busy for twenty minutes, origin is pushed and the next run pushes the Space. A push that is not a fast-forward (someone pushed to the Space by hand) is refused and reported, never forced. Nothing here touches prod. Where to look: `logs/pipeline.log`, the `pipeline_status` and `list_deployments` tools (ask the Task Manager agent "what shipped to test today"), the Pipeline tab of the Team Tracker Liveboard, the `pipeline_runs` and `deployments` tables. ## The agent The agent is a row in `tracker_people` (`is_agent`); tasks are assigned to it like to anyone. `scripts/agent_worker.sh` takes its top open task, cuts `agent/t-` off `develop` in its own worktree, runs Claude Code with `scripts/agent_worker_prompt.md`, and if a commit resulted, pushes the branch and opens the PR under boone's credentials. The agent has no GitHub login; the `agent/` prefix is what keeps its PRs off the auto-approve path. Run the worker by hand or add it to launchd beside the pickup run. ## One-time setup 1. **Supabase.** Run `demoprep_app/tracker/schema.sql` in the project's SQL editor (idempotent), then the `tracker_reader` role lines at its bottom with a password. 2. **`develop` to the test tip, once.** In the main checkout: ```bash git fetch hf-mcp-test origin git branch -f develop hf-mcp-test/main git push origin develop ``` It is a fast-forward (origin's `develop` is an ancestor of the test tip). Retarget Jack's open PRs to `develop`: `gh pr edit --base develop`. 3. **The test Space env:** `GITHUB_TOKEN`, `TRACKER_REPOS=boone10/DemoPrep,thoughtspot/tse_demos`, `TRACKER_INTEGRATION_BRANCH=develop`. Setting a variable restarts the Space: check `status` first. The token is a GitHub fine-grained personal access token (Settings, Developer settings, Personal access tokens, Fine-grained) with: Repository access "Only select repositories" including `boone10/DemoPrep`; Repository permissions **Pull requests: Read-only** (Metadata: Read-only comes with it). Optional, for the `checks` column once GitHub Actions exist: Checks and Commit statuses, Read-only; without them the sync records "none". A token missing Pull requests answers 403 "Resource not accessible by personal access token" on the first sync (seen 2026-10-22). Editing the token's permissions keeps its value, so the Space secret need not change. Only the test Space gets `TRACKER_REPOS`: the sync runs in one place. 4. **The Mac:** `gh` and `claude` on PATH, `gh auth login` as boone10; `cp scripts/launchd/com.demoprep.pipeline.plist ~/Library/LaunchAgents/ && launchctl load ~/Library/LaunchAgents/com.demoprep.pipeline.plist`. The first run creates the `pipeline/` worktree. `MCP_ACCESS_TOKEN` and `HF_TOKEN` are already in `.env`. 5. **ThoughtSpot:** the Supabase Tracker connection and the TML in `demoprep_app/tracker/tml/` (see the agent doc). ## Not in this version, on the list - GitHub Actions running the suite on every PR (the pickup run runs it for now). - Slack intake from the SC demo tools channel: AgentSpot reads it with boone's login and calls `create_task`; nothing server-side. - Test to staging to prod: boone, by hand, until the test line has run this way for a while.